2010-05-13 111 views
1

我有一長串的鏈接,我使用下面的代碼,總票數,提交的,通常的東西吐出來,但我不是100%如何確定當前登錄用戶已投票的鏈接或不。我知道如何從我的視野內做到這一點,但我是否需要改變我的下面的視圖代碼,或者我可以使用模板的工作方式來確定它?Django:確定用戶是否投了票

我已閱讀Django Vote Up/Down method,但我不太明白髮生了什麼事情(並且不需要任何文字說明)。

模型(片段):

class Link(models.Model): 
    category = models.ForeignKey(Category, blank=False, default=1) 
    user = models.ForeignKey(User) 
    created = models.DateTimeField(auto_now_add=True) 
    modified = models.DateTimeField(auto_now=True) 
    url = models.URLField(max_length=1024, unique=True, verify_exists=True) 
    name = models.CharField(max_length=512) 

    def __unicode__(self): 
     return u'%s (%s)' % (self.name, self.url) 

class Vote(models.Model): 
    link = models.ForeignKey(Link) 
    user = models.ForeignKey(User) 
    created = models.DateTimeField(auto_now_add=True) 

    def __unicode__(self): 
     return u'%s vote for %s' % (self.user, self.link) 

意見(摘錄):

def hot(request): 
    links = Link.objects.select_related().annotate(votes=Count('vote')).order_by('-created') 
    for link in links: 
     delta_in_hours = (int(datetime.now().strftime("%s")) - int(link.created.strftime("%s")))/3600 
     link.popularity = ((link.votes - 1)/(delta_in_hours + 2)**1.5) 
     if request.user.is_authenticated(): 
      try: 
       link.voted = Vote.objects.get(link=link, user=request.user) 
      except Vote.DoesNotExist: 
       link.voted = None 

    links = sorted(links, key=lambda x: x.popularity, reverse=True) 

    links = paginate(request, links, 15) 

    return direct_to_template(
     request, 
     template = 'links/link_list.html', 
     extra_context = { 
      'links': links, 
     }) 

以上觀點實際上完成我需要什麼,但我認爲是一個可怕的低效的方式。這導致了可怕的n + 1查詢,因爲它代表了33個查詢包含29個鏈接的頁面,而最初我只有4個查詢。我真的更喜歡用Django的ORM或至少.extra()來做到這一點。

有什麼建議嗎?

編輯

@Gabriel赫利

我試圖重新您的回答,我會有不同的結果,讓我告訴雅我得到了什麼。

views.py

links = Link.objects.select_related().extra(
    select={ 
     'votes': 'COUNT(links_vote.id)', 
     'voted': 'SELECT COUNT(links_vote.id) FROM links_vote WHERE links_vote.user_id = 1 AND links_vote.link_id = links_link.id', 
    }, 
    tables = ['links_vote'] 
) 

models.py

class Vote(models.Model): 
    link = models.ForeignKey(Link) 
    user = models.ForeignKey(User) 
    created = models.DateTimeField(auto_now_add=True) 

    class Meta: 
     unique_together = ('link', 'user') 

    def __unicode__(self): 
     return u'%s vote for %s' % (self.user, self.link) 

但它返回一個錯誤:

subquery uses ungrouped column "links_link.id" from outer query 

LINE 1:... E links_vote.user_id = 1 AND links_vote.link_id = links_link ...

所生成的查詢看起來是(精確地)是這樣的:

SELECT (SELECT COUNT(links_vote.id) FROM links_vote WHERE links_vote.user_id = 1 AND links_vote.link_id = links_link.id) AS "voted", "links_link"."id", "links_link"."category_id", "links_link"."user_id", "links_link"."created", "links_link"."modified", "links_link"."url", "links_link"."name", "links_category"."id", "links_category"."name", "auth_user"."id", "auth_user"."username", "auth_user"."first_name", "auth_user"."last_name", "auth_user"."email", "auth_user"."password", "auth_user"."is_staff", "auth_user"."is_active", "auth_user"."is_superuser", "auth_user"."last_login", "auth_user"."date_joined" FROM "links_link" INNER JOIN "links_category" ON ("links_link"."category_id" = "links_category"."id") INNER JOIN "auth_user" ON ("links_link"."user_id" = "auth_user"."id") , "links_vote" 

我使用PostgreSQL我知道愛GROUP BY但我不是如何糾正這種100%。 。

EDIT 2(主要進展)

鏈接= Link.objects.select_related()註釋(票=計數( '投票'))的額外( 選擇= { # '投票': 'SELECT COUNT()FROM links_vote WHERE links_vote.user_id =%s AND links_vote.link_id = links_link.id'%(request.user.id), #'voteed':''%(request.user.id), ''voteed':'SELECT CASE WHEN links_vote.user_id =%s THEN 1 ELSE 0 END'%(request.user.id), #'voteed':'SELECT COUNT()FROM links_vote WHERE links_vote.link_id = links_link.id和links_vote.u ser_id =%s'%(request.user.id), }, 其中= ['links_link.id = links_vote.link_id'], )。ORDER_BY(「 - 創建」)

*從這裏應用補丁的漏洞後,這僅適用於(http://code.djangoproject.com/ticket/11916

我如此接近發現最後一塊,我需要確定用戶是否已經投票。 ..

回答

2

我已經處理了在此之前,並與extra解決或多或少像這樣:

# annotate whether you've already voted on this item 
table = Vote._meta.db_table 
select = 'SELECT COUNT(id) FROM %s' %table 
where1 = 'WHERE ' + table + '.user_id = %s' 
where2 = 'AND ' + table + '.item_id = appname_item.id' 
items = items.extra(
     select={'votes':" ".join((select, where1, where2,))}, 
     select_params=(request.user.id,) 
    ) 

實際上,這需要項目的查詢集和詮釋每一個與0或者一定數量的票。在我的系統中,我在投票上使用unique_together = ('link', 'user')以確保每個用戶只能投票一次,因此註釋的數據是0或1(實際爲布爾值)。它工作得很好,避免了n + 1問題。

+0

我有幾個問題不適合在這裏,看看我上面的編輯。雖然謝謝!我覺得這讓我走上了正軌。 – TheLizardKing 2010-05-13 21:16:34