Django注释返回重复条目

Posted

技术标签:

【中文标题】Django注释返回重复条目【英文标题】:Django annotate returning duplicate entries 【发布时间】:2021-12-26 08:50:23 【问题描述】:

我正在像这样注释查询集:

class ItemQuerySet(models.QuerySet):
    def annotate_subitem_stats(self):
        return self.annotate(
            count_subitems=Count('subitems'),
            has_sent_subitems=Case(
                When(subitems__status=Status.sent, then=Value(True)),
                default=Value(False)
            ),
        )

在本例中,SubItem 是一个模型,其外键指向 Item

当我运行此代码时发生了一个奇怪的行为。假设我们有 1 个Item 和 2 个SubItems 链接到它。一个子项已发送状态,而另一个则没有。当我在查询集上运行注释时,查询集返回该项目两次,一次将has_sent_subitems 设置为True,另一次设置为False。另一个奇怪的是,一个重复有count_subitems == 1,另一个有count_subitems == 1,好像查询集已经将项目分成两行,一个在status == 'sent',另一个在status != 'sent'

这基本上就是带注释的查询集的样子:

[
    
        'name': 'Item Name',
        'count_subitems': 1,
        'has_sent_subitem': False
    ,
    
        'name': 'Item Name',
        'count_subitems': 1,
        'has_sent_subitem': True
    
]

这是数据库的样子,使用伪代码:

item = Item()
SubItem(item=item, status=draft)
SubItem(item=item, status=sent)

我很确定这与When(subitems__status=Status.sent, then=Value(True)), 行有关。有什么办法可以让那行检查是否只有 1 个项目已发送状态,然后将注释设置为 true 并继续?

附:使用 .distinct() 不起作用。我不能使用.distinct(field),因为annotate() + distinct(fields) is not implemented.

【问题讨论】:

【参考方案1】:

您可以改为使用Exists 子查询,以避免subitems__status 引起的连接,所以:

from django.db.models import Exists, OuterRef


class ItemQuerySet(models.QuerySet):
    def annotate_subitem_stats(self):
        return self.annotate(
            count_subitems=Count('subitems'),
            has_sent_subitems=Exists(
                SubItem.objects.filter(item=OuterRef('pk'), status=Status.sent)
            ),
        )

【讨论】:

我想知道,由于SubItem.objects.filter 调用,这是否会触发查询集中每个项目的查询? 不应该,因为子查询仍然是“主”查询的一部分

以上是关于Django注释返回重复条目的主要内容,如果未能解决你的问题,请参考以下文章

“返回该页面可能会导致您重复执行的任何操作” - Django

python 删除重复条目 - Django

Django 模型保存和“键 PRIMARY 的重复条目”

Django admin,多对多字段,多个重复条目

检查数组中的重复条目,但仅返回重复的值 [重复]

在 django 中获取重复项