【问题标题】:How to do SELECT COUNT(*) GROUP BY and ORDER BY in Django?如何在 Django 中执行 SELECT COUNT(*) GROUP BY 和 ORDER BY?
【发布时间】:2013-10-06 18:08:19
【问题描述】:

我正在使用事务模型来跟踪通过系统的所有事件

class Transaction(models.Model):
    actor = models.ForeignKey(User, related_name="actor")
    acted = models.ForeignKey(User, related_name="acted", null=True, blank=True)
    action_id = models.IntegerField() 
    ......

如何获得系统中排名前 5 的演员?

在sql中基本上会是

SELECT actor, COUNT(*) as total 
FROM Transaction 
GROUP BY actor 
ORDER BY total DESC

【问题讨论】:

标签: django django-queryset


【解决方案1】:

如果您想要反转(较大的值到较小的值)顺序,只需使用- 减号。

from django.db.models import Count
Transaction.objects.all().values('actor').annotate(total=Count('actor')).order_by('-total')

【讨论】:

    【解决方案2】:

    根据文档,您应该使用:

    from django.db.models import Count
    Transaction.objects.all().values('actor').annotate(total=Count('actor')).order_by('total')
    

    values() : 指定哪些列将用于“分组”

    Django 文档:

    "当使用 values() 子句来约束 在结果集中返回,评估注释的方法是 稍微不一样。而不是为每个返回一个带注释的结果 结果在原始QuerySet中,原始结果被分组 根据指定的字段的唯一组合 values() 子句"

    annotate() : 指定对分组值的操作

    Django 文档:

    第二种生成汇总值的方法是为 QuerySet 中的每个对象生成一个独立的汇总。例如,如果您 正在检索书籍列表,您可能想知道有多少作者 为每本书做出贡献。每本书都有多对多的关系 与作者;我们想为每本书总结这种关系 在查询集中。

    可以使用 annotate() 子句生成每个对象的摘要。 当指定 annotate() 子句时,QuerySet 中的每个对象 将使用指定的值进行注释。

    order by 子句是不言自明的。

    总结一下:您分组,生成作者查询集,添加注释(这将为返回的值添加一个额外的字段),最后,您按此值对它们进行排序

    请参阅https://docs.djangoproject.com/en/dev/topics/db/aggregation/ 了解更多信息

    注意:如果使用 Count,传递给 Count 的值不会影响聚合,只是赋予最终值的名称。聚合器按值的唯一组合(如上所述)进行分组,而不是按传递给 Count 的值。以下查询相同:

    Transaction.objects.all().values('actor').annotate(total=Count('actor')).order_by('total')
    Transaction.objects.all().values('actor').annotate(total=Count('id')).order_by('total')
    

    【讨论】:

    • 对我来说它是 Transaction.objects.all().values('actor').annotate(total=Count('actor')).order_by('total'),别忘了从 django.db.models 导入 Count。谢谢
    • 请注意:如果使用Count(可能还有其他聚合器),传递给Count 的值不会影响聚合,只是赋予最终值的名称。聚合器按 values(如上所述)的唯一组合进行分组,而不是按传递给 Count 的值。
    • 您甚至可以将它用于 postgres 搜索结果查询集以获取分面!
    • @kronosapiens 它确实会影响它,至少现在(我使用的是 Django 2.1.4)。在示例中,total 是给定的名称,sql 中使用的计数是 COUNT('actor'),在这种情况下无关紧要,但如果例如values('x', 'y').annotate(count=Count('x')),你会得到COUNT(x),而不是COUNT(*)COUNT(x, y),只是在./manage.py shell 中尝试过
    • 这个答案已经很多年了,但是没有人指出: .order_by('total') 应该是 .order_by('-total') 因为 OP 要求 DESC order by
    【解决方案3】:

    就像@Alvaro 已经回答了 Django 的直接等价物 GROUP BY 声明:

    SELECT actor, COUNT(*) AS total 
    FROM Transaction 
    GROUP BY actor
    

    是通过使用values()annotate()方法如下:

    Transaction.objects.values('actor').annotate(total=Count('actor')).order_by()
    

    但还必须指出一件事:

    如果模型在class Meta 中定义了默认排序,则必须使用.order_by() 子句才能获得正确的结果。 即使不打算排序,您也不能跳过它。

    此外,对于高质量的代码,建议始终在annotate() 之后放置一个.order_by() 子句,即使没有class Meta: ordering。这种方法将使声明经得起未来考验:无论将来对class Meta: ordering 进行任何更改,它都会按预期工作。


    让我举个例子。如果模型有:

    class Transaction(models.Model):
        actor = models.ForeignKey(User, related_name="actor")
        acted = models.ForeignKey(User, related_name="acted", null=True, blank=True)
        action_id = models.IntegerField()
    
        class Meta:
            ordering = ['id']
    

    那么这种方法行不通:

    Transaction.objects.values('actor').annotate(total=Count('actor'))
    

    这是因为 Django 对class Meta: ordering 中的每个字段都执行了额外的GROUP BY

    如果您要打印查询:

    >>> print Transaction.objects.values('actor').annotate(total=Count('actor')).query
      SELECT "Transaction"."actor_id", COUNT("Transaction"."actor_id") AS "total"
      FROM "Transaction"
      GROUP BY "Transaction"."actor_id", "Transaction"."id"
    

    很明显,聚合不会按预期工作,因此必须使用.order_by() 子句来清除此行为并获得正确的聚合结果。

    在官方 Django 文档中查看:Interaction with default ordering or order_by()

    【讨论】:

    • .order_by() 在 Meta 中将我从 ordering 中救了出来。
    • “如果模型在 Meta 类中定义了默认排序,则必须使用 .order_by() 子句才能获得正确的结果。”谢谢你。这不起作用,并且添加 order_by 修复了它。要求一个 order_by 来做一个 group by work 很直观,理解 Django 的 ORM 的一个重要的怪癖。
    猜你喜欢
    • 2019-01-27
    • 1970-01-01
    • 2012-05-06
    • 1970-01-01
    • 1970-01-01
    • 2021-08-01
    • 2011-04-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多