2016-07-25 2 views
1

私は適切に解決できないような再発の問題があります。私のサイトは仕事のサイトに似ています。そこでは、人々は仕事(そしてその中の詳細)を投稿することができ、他の人はブックマークすることができます。各ジョブは、明らかに複数のビューアにブックマークすることができます。複数のテーブルからのデータを表示する最良の方法

class Job(models.Model): 
    user = models.ForeignKey(User, on_delete=models.CASCADE) 
    title = models.CharField(max_length=150) 
    description = models.CharField(max_length=5000) 


class Bookmark(models.Model): 
    user = models.ForeignKey(User, on_delete=models.CASCADE) 
    job = models.ForeignKey(Job, on_delete=models.CASCADE) 

私の意図は、ホームページ内のすべてのジョブを表示することで、複数のユーザーからの複数のジョブを意味します

はそうここmodel.pyです。他のユーザーは小さなブックマークアイコンをクリックしてブックマークしたり、ブックマークを解除することができます。これと同じように:

def index(request): 
    context = {} 
    populateContext(request, context) 

    jobs = Job.objects.all().order_by('-id') 

    context = {'jobs': jobs} 


    return render(request, 'templates/index.html', context) 

は非常にシンプルだと思い、私の意図です:

ここview.pyです。テンプレートの外観は次のとおりです。

{% for job in jobs %} 
    <div> 
     {{ job.title }}<br> 
     {{ job.description }}<br> 
     by {{ job.user.username }} 
    </div> 
{% endfor %} 

私の質問は、各ユーザー固有のブックマーク状態を表示する方法です。ここに私の現在の解決策があります:

{% for job in jobs %} 
    <div> 
     {{ job.title }}<br> 
     {{ job.description }}<br> 
     by {{ job.user.username }}<br> 

     {% for watch in job.bookmark_set.all %} 
      {% if watch.user_id = request.user.id %} 
       You have bookmarked this! <a>Unbookmark!</a> 
      {% endif %} 
     {% endfor %} 

     <a>Bookmark</a> 
    </div> 
{% endfor %} 

"Unbookmark!"リンクは途中で「ブックマーク」リンク上に配置されます。ブックマークテーブルには、特定のジョブのブックマークが0個以上含まれていても、複数のユーザーの下にブックマークが含まれているため、上記の解決策はそのように機能します。私はview.pyで、ログインしたユーザが作成したジョブだけをフィルタリングすることでこれを処理します。しかし、私はindex.htmlがそれらをすべて表示しているので、特に仕事でフィルタリングすることはできません。

bookmarked = Bookmark.objects.all().filter(user_id=request.user.id) 

を...、それがログインしたユーザが作っていたことを別のジョブのすべてのブックマークを一覧表示になります。したがって、たとえば、私は...これを吐き出すことができます。私はまだ、テンプレート内のフィルタリングする必要があるので、各プロジェクトが各ブックマークに一致するようにする必要があり、これは不可能であると私は理解しています。

とにかく、これはかなり非効率的だと思います。だから私はこれを扱う簡単な方法があるのだろうかと思っていたのですか?この方法で作業するようにすることをお勧めします。

{% for job in jobs %} 
    <div> 
     {{ job.title }}<br> 
     {{ job.description }}<br> 
     by {{ job.user.username }}<br> 

     {% if job.id = bookmark.job.id %} 
      You have bookmarked this! <a>Unbookmark!</a> 
     {% else %} 
      <a>Bookmark</a> 
     {% endif %} 
    </div> 
{% endfor %} 

ありがとうございました!

答えて

3

conditional expressionsを使用して、jobsにこの情報を注釈付けることができます。ビューで:

from django.db.models import Case, IntegerField, Sum, When 

jobs = Job.objects.annotate(
      is_bookmarked=Sum(Case(
       When(bookmark__user=request.user, then=1), 
       default=0, output_field=IntegerField() 
      ))).order_by('-id') 

jobは現在1(ユーザーがジョブをブックマークしている)または0のいずれかであるis_bookmarked性質を有しています。あなたのテンプレートで:

{% for job in jobs %} 
    <div> 
     {% if job.is_bookmarked %} 
      You have bookmarked this! <a>Unbookmark!</a> 
     {% else %} 
      <a>Bookmark</a> 
     {% endif %} 
    </div> 
{% endfor %} 

あなたが念頭に置いておいた他のアプローチも同様です(上記の方法よりは効率は低いが)。ビューで:

テンプレートで
jobs = Job.objects.all().order_by('-id') 
# Get a list of all Job IDs bookmarked by this user 
user_bookmarks = Bookmark.objects.filter(user_id=request.user.id)\ 
           .values_list('job__id', flat=True) 

{% for job in jobs %} 
    <div> 
     {% if job.id in user_bookmarks %} 
      You have bookmarked this! <a>Unbookmark!</a> 
     {% else %} 
      <a>Bookmark</a> 
     {% endif %} 
    </div> 
{% endfor %} 

これらの両方のアプローチはほとんど同じロジックをしている - の違いは、最初のものは、一般的に、より効率的であるデータベース・レベルでこれを行うことであること。

+0

エレガントなソリューション! – gglasses

+0

詳細なソリューションと説明をありがとうございました! 2番目のアプローチは完全に機能します。しかし、最初のものはそうではありません。ジョブがブックマークされている場合、ジョブは2回表示されます(ブックマークされていない場合とブックマークの場合)。 また、両方のアプローチに速度差がありますか? – Bob

+0

ええと、最初のアプローチを修正して動作させてみましょう... DBクエリとリストフィルタリングを必要とせず、より効率的です。 – solarissmoke

関連する問題