如果存在特定外键,则使用信息注释查询集

时间:2015-11-26 17:49:29

标签: django django-models

说我有两个这样的模型:

from django.contrib.auth import User

class Post(models.Model):
  text = models.TextField()

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

我觉得很标准。用户可以喜欢的帖子表。 我想获取所有Post对象的查询集,如果当前用户(想象request.user)喜欢它们,则使用该信息进行注释。

这样的事情(这当然是不正确的)

qs = Post.objects.all().annotate(like__user=request.user)

我想迭代qs并有一个属性说明当前用户是否喜欢这个帖子,如下所示:

for post in qs:
  if post.current_user_liked:
    # do something

我想使用注释的原因当然是性能,我想避免对每个帖子进行查询以检查是否存在Like with user = request.user。

2 个答案:

答案 0 :(得分:4)

我认为您可以annotate()RawSQL一起使用。

如果这不起作用,您可以将prefetch_relatedPrefetch对象一起使用,以便Django通过一个额外查询加载所有相关的喜欢。

Post.objects.all().prefetch_related(
    Prefetch('current_user_likes', queryset=Like.objects.filter(user=request.user))
)

然后当你遍历查询集时,你会这样做:

for post in qs:
    if post.current_user_likes.all():
        # do something

请注意,您在此处使用all(),因为已经提取了结果。通常exists()如果你不需要结果会更有效率,但在这里它会引起额外的查询。

答案 1 :(得分:1)

我最终采用了一种更简单的方法,因为我在视图中使用分页显示Post个对象,因此Post的{​​{1}}总是非常小。 另外,我显示由pk排序的queryset个对象。

所以我的解决方案是构建Post主要Post主键的python列表,从我正在显示的帖子中选择(因此列表总是非常小):

request.user

然后在我的模板中,我只需检查每个pks = [ post.pk for post in queryset ] first = pks[0] last = pks[-1] context['liked_posts'] = Like.objects.filter(user=request.user, post_id__range=sorted([first, last])).values_list('post_id', flat=True) pk是否在Post列表中。

此方法仅需要对数据库进行额外查询。