【问题标题】:Using Django annotate(Count) with a nullable ForeignKey将 Django annotate(Count) 与可为空的 ForeignKey 一起使用
【发布时间】:2011-06-24 19:15:19
【问题描述】:

使用来自https://docs.djangoproject.com/en/dev/topics/db/queries/的示例模型

我想做如下的事情:

q = Entry.objects.filter(...)
entries = q.all().order_by('pub_date')
blog_counts = q.values('blog__name').annotate(Count('blog'))

这给了我如下结果:

[{'blog__count': 3, 'blog__name': u'Cheddar Talk'}, {'blog__count': 5, 'blog__name': u'Beatles Blog'}]

如果 Entry.blog ForeignKey 设置为“null=True,blank=True”,并且我为博客创建了几个具有 null 值的 Entry 记录,我会得到如下信息:

[{'blog__count: 0, 'blog__name': None}, {'blog__count': 3, 'blog__name': u'Cheddar Talk'}, {'blog__count': 5, 'blog__name': u'Beatles Blog'}]

我希望获得没有关联博客的实际条目数,而不是 0。查看执行的 SQL,我发现它正在执行 COUNT(blog.id) 而不是 COUNT(@987654327 @.blog_id),但更改为 .annotate(Count('blog_id')) 给了我:

FieldError: Cannot resolve keyword 'blog_id' into field.

在没有相关博客的情况下,我如何才能获得准确的条目计数?

【问题讨论】:

    标签: django


    【解决方案1】:

    生成的SQL语句使用Count(<field_name>)形式的count子句,不计算空值。不幸的是(至少 MySQLPostgreSQL)后端将 null 值包含到输出中,即使 null 不计算在内!这给用户留下了根本没有空值的错误印象。

    解决方案

    生成的 SQL 语句必须采用Count(*) 格式,而不是Count(<field_name>)。这将导致正确的空值计数。

    blog_counts = q.values('blog__name').annotate(Count('*'))
    

    见票:

    https://code.djangoproject.com/ticket/15183

    【讨论】:

      【解决方案2】:
      Entry.objects.filter(blog__isnull=True).count()
      

      这会给你你想要的。在您当前的代码中,Count 提供的正是您所要求的,即每个条目关联的博客数量。对于那些有空博客的情况,显然是零。

      【讨论】:

      • 另外,如果你一心想要使用 annotate,你也许可以摆脱 Count('blog__blog_id') 我不怎么玩 annotate 所以我不确定这是否可行或不是。
      • 不会。 blog_id 必须是 Blog 的属性。不是,所以会引发异常。
      • 这个想法是获得每个博客的准确计数,以及没有关联博客的条目的计数。单独检索空值的计数会起作用,但我仍然必须忽略列表中的 0 计数。似乎应该有更好的方法。
      • 布莱斯,我正在寻找的 COUNT() 类型直观地是由更像 Count('entry__blog_id') 的东西生成的,但这也不起作用。
      • Count 有点让人头疼。文档简单地说它计算“相关对象”的数量。它的用法很明显,例如 ManyToManyField 甚至外键的反向关系 (Blog.objects.annotate(Count(entry)))。它从字面上计算相关对象。在外键的前向关系上,它采用一种替代行为,即对该外键具有相同值的对象实例进行计数。问题是用于将 NULL 视为不可数的方法,导致您的 0s。
      猜你喜欢
      • 2016-01-23
      • 1970-01-01
      • 2017-09-16
      • 1970-01-01
      • 2019-01-01
      • 1970-01-01
      • 2021-11-28
      • 1970-01-01
      • 2016-05-11
      相关资源
      最近更新 更多