Django:用过滤器注释计数
Django: annotate Count with filter
我有 "post" 个对象和一个 "post like" 个对象,其中 post 收到了哪个用户的点赞数:
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)
我可以 select 像这样 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)
有效。现在,我如何 filter 当前用户的 Count
聚合?我想检索的不是所有 post 的点赞,而是 登录用户 的所有点赞。结果 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)
先尝试添加过滤器:
Post.objects.filter(postlike__user=request.user).annotate(likes=Count('postlike'))
来自docs:
The filter precedes the annotation, so the filter constrains the objects considered when calculating the annotation.
它不是很干净,但你可以使用 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。
你知道 Count
有一个 filter
论点吗?
Post.objects.annotate(
likes=Count('postlike', filter=Q(postlike__user=logged_in_user))
)
我有 "post" 个对象和一个 "post like" 个对象,其中 post 收到了哪个用户的点赞数:
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)
我可以 select 像这样 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)
有效。现在,我如何 filter 当前用户的 Count
聚合?我想检索的不是所有 post 的点赞,而是 登录用户 的所有点赞。结果 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)
先尝试添加过滤器:
Post.objects.filter(postlike__user=request.user).annotate(likes=Count('postlike'))
来自docs:
The filter precedes the annotation, so the filter constrains the objects considered when calculating the annotation.
它不是很干净,但你可以使用 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。
你知道 Count
有一个 filter
论点吗?
Post.objects.annotate(
likes=Count('postlike', filter=Q(postlike__user=logged_in_user))
)