2016-01-18 55 views
1

我有一個投票系統,用戶可以在帖子上投下或投票。投票將用於計算,所以我需要以日誌格式存儲它們,即我將每張投票保存在自己的表中。查詢Django每個用戶每個帖子的最新投票

事情是這樣的:

class PointLog(models.Model): 
    post = models.ForeignKey(Post, db_index=True) 
    points = models.IntegerField(db_index=True) 
    user = models.ForeignKey(User, blank=True, null=True) 
    time = models.DateTimeField(auto_now_add=True, db_index=True) 
    data = models.IntegerField() # -1, 0 or 1 

現在我需要顯示20個職位,其中最後一投的用戶一起做。

我使用django-rest-framework,所以我可以使用看起來像這樣的序列化程序字段; uservote = serializers.SerializerMethodField(),再加上像一個函數:

def get_uservote(self, obj): 
    user = self.context['request'].user 
    vote = PointLog.objects.only('data').filter(user=user, post=obj).last() 
    return vote.data if vote else 0 

但會做每一個後DB-查詢1次,我希望有一個更好的解決方案。

通過將queryset保存在self.context中,每次運行get_uservote時我都可以保存一個db-query,以便覆蓋該部分。 但我怎麼能做一個查詢,基於項目列表返回所有latest數據從另一個表。

一開始就是PointLog.objects.filter(user=user, post__in=posts),但接下來呢?這甚至有可能在1查詢中使用原始SQL?

更新1PointLog.objects.filter(...).order_by('post__id').distinct('post__id')還挺會做,但我不認爲我保證能得到newest投票。如果我使用order_by('pk')(或'time'),我不能使用distinct('post__id'),因爲我將得到一個sql錯誤(ProgrammingError: SELECT DISTINCT ON expressions must match initial ORDER BY expressions

回答

0

我發現一個解決方案只添加了一個額外的查詢。

完整的get_uservote工作將是;

def get_uservote(self, obj): 
    user = self.context['request'].user 
    if user.is_authenticated(): 
     if not self.context.get('get_uservote_data'): 
      self.context['get_uservote_data'] = {i.post_id: i.data for i in PointLog.objects.filter(user=user, post__in=self.instance).order_by('post__id', '-pk').distinct('post__id')} 
     return self.context['get_uservote_data'].get(obj.id, 0) 
    else: 
     return 0 # Return 0 as "not voted" if not logged in 

請注意,我們在這裏做了一些技巧;

  • 將數據存儲在self.context['get_uservote_data']中,因此我們只需要一次運行查詢。
  • 使用i.post_id作爲我們數據的關鍵字,而不是i.post.id。詢問i.post.id這裏會觸發每個項目1個查詢。
  • self.instance是包含我們要過濾的所有帖子的查詢集。

這一切都導致了一個查詢,看起來像這樣:

SELECT DISTINCT ON ("post_pointlog"."post_id") "post_pointlog"."id", 
               "post_pointlog"."post_id", 
               "post_pointlog"."data" 
FROM "post_pointlog" 
WHERE ("post_pointlog"."user_id" = 20 
     AND "post_pointlog"."post_id" IN (1, 2, 3, 4)) 
ORDER BY "post_pointlog"."post_id" ASC, 
      "post_pointlog"."id" DESC 
相關問題