2016-07-25 20 views
1

我有我似乎無法充分解決經常出現的問題顯示的數據。我的網站是類似於一個工作現場,在那裏,人們可以發佈(內和詳細信息)的工作,其他人可以收藏tthem。每個工作顯然可以被多個查看者加入書籤。最好的辦法從多個表

所以這裏的model.py:

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) 

我的目的是要顯示在網頁中的所有作業,這意味着來自多個用戶的多個作業。其他用戶可以點擊一個小書籤圖標來爲其添加書籤,或者取消其書籤。像這樣:

這裏的view.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) 

很簡單,我認爲,這是我的本意。以下是模板的外觀:

{% 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!」鏈接將被定位在「書籤」鏈接上。上面的解決方案是這樣工作的,因爲書籤表將包含零個或多個特定作業的書籤,但在多個用戶下。我會通過過濾登錄用戶所做的作業來處理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現在有一個is_bookmarked屬性其是1(用戶書籤的作業)或0。在您的模板中:

{% 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

非常感謝您的詳細解答和解釋!第二種方法完美地工作。但是,第一個沒有。如果作業已添加書籤,則會顯示作業兩次(一次未添加書籤,另一次添加書籤)。 此外,兩種方法之間有速度差異嗎? – Bob

+0

嗯,讓我試着修復第一種方法,以便它可以工作......它更高效,因爲它只需要在數據庫查詢和沒有列表過濾。 – solarissmoke