Django:为什么注释将项目添加到我的查询集中?

Django: why does annotate add items to my queryset?

我正在努力做一些简单的事情。 我有 Item objects,用户可以将它们标记为收藏夹。 由于这些项目不属于用户,所以我决定在 UserItem 之间使用 ManyToMany 来记录收藏关系。如果用户在 favoriters 项字段中,则表示用户收藏了它。

然后,当我为特定用户检索 objects 时,我想注释每个项目以指定它是否被用户收藏。我为此制作了 add_is_favorite_for() 方法。

这是(简化的)代码:

class ItemQuerySet(query.QuerySet):
    def add_is_favorite_for(self, user):
        """add a boolean to know if the item is favorited by the given user"""
        condition = Q(favoriters=user)
        return self.annotate(is_favorite=ExpressionWrapper(condition, output_field=BooleanField()))

class Item(models.Model):
    objects = Manager.from_queryset(ItemQuerySet)()

    favoriters = models.ManyToManyField(settings.AUTH_USER_MODEL, blank=True)

这没有按预期工作,Django 似乎为每个 收藏该项目的用户添加了一个项目。它会导致疯狂的事情,例如:

Item.objects.count() # 10
Item.objects.add_is_favorite_for(some_user).count() # 16 -> how the hell an annotation can return more results than initial queryset?

我在这里遗漏了一些东西...

您可以更改注释中的条件以使用子查询,获取用户收藏的所有商品,然后测试商品的 ID 是否在子查询中。

这应该可以解决您的重复问题:

def add_is_favorite_for(self, user):
    return self.annotate(is_favorite=ExpressionWrapper(
        Q(id__in=Item.objects.filter(favoriters=user).values('id')),
        output_field=BooleanField()
    ))