就像@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()。