Django:使用过滤器注释Count

时间:2017-10-18 07:10:40

标签: python django django-models django-orm

我有“发布”对象和“帖子之类”对象,其中有多少人喜欢某个帖子已被哪个用户收到:

class Post(models.Model):
    text     = models.CharField(max_length=500, default ='')
    user     = models.ForeignKey(User)

class PostLike(models.Model):
    user    = models.ForeignKey(User)
    post    = models.ForeignKey(Post)

我可以选择收到的帖子有多少像这样:

Post.objects.all().annotate(likes=Count('postlike'))

这大致转换为:

SELECT p.*,
       Count(l.id) AS likes
    FROM post p, postlike l
    WHERE p.id = l.post_id
    GROUP BY (p.id)

有效。现在,我如何过滤当前用户的Count聚合?我想要检索不是所有这些帖子的内容,而是所有喜欢的记录用户。生成的SQL应该是:

SELECT p.*,
    (SELECT COUNT(*) FROM postlike WHERE postlike.user_id = 1 AND postlike.post_id = p.id) AS likes
FROM post p, postlike l
WHERE p.id = l.post_id
GROUP BY (p.id)

3 个答案:

答案 0 :(得分:2)

您知道Count有一个filter参数吗?

Post.objects.annotate(
    likes=Count('postlike', filter=Q(postlike__user=logged_in_user))
)

答案 1 :(得分:1)

首先尝试添加过滤器:

Post.objects.filter(postlike__user=request.user).annotate(likes=Count('postlike'))

来自docs

  

过滤器位于注释之前,因此过滤器会约束计算注释时考虑的对象。

答案 2 :(得分:1)

它并不完全干净,但您可以使用Case/When ...

posts = Post.objects.all().annotate(likes=models.Count(
  models.Case(
    models.When(postlike__user_id=user.id, then=1),
    default=0,
    output_field=models.IntegerField(),
  )
))

当然,当你无法通过Django ORM表达某些内容时,你总是可以下载到.extra()甚至原始SQL。