就像@Alvaro回答了Django直接等效的for 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()
子句对于获得正确的结果是必需的。即使不打算订购,您也不能跳过它。
此外,对于高质量的代码,即使没有,也建议始终.order_by()
在其后放置一个子句。这种方法将使该语句适应未来发展:无论将来对进行任何更改,它都将按预期工作。annotate()
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 GROUP BY
在其中的每个字段上都执行附加操作class Meta: ordering
如果要打印查询:
>>> 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官方文档中的order_by()的交互。