Assim como @Alvaro respondeu ao equivalente direto do Django para a GROUP BY
declaração:
SELECT actor, COUNT(*) AS total
FROM Transaction
GROUP BY actor
é por meio do uso dos métodos values()
e da annotate()
seguinte maneira:
Transaction.objects.values('actor').annotate(total=Count('actor')).order_by()
No entanto, mais uma coisa deve ser apontada:
Se o modelo tiver uma ordenação padrão definida em class Meta
, a .order_by()
cláusula é obrigatória para resultados adequados. Você simplesmente não pode ignorá-lo, mesmo quando nenhum pedido é pretendido.
Além disso, para um código de alta qualidade, é aconselhável sempre colocar uma .order_by()
cláusula após annotate()
, mesmo quando não houver class Meta: ordering
. Essa abordagem tornará a declaração à prova de futuro: ela funcionará exatamente como pretendido, independentemente de quaisquer alterações futuras em class Meta: ordering
.
Deixe-me dar um exemplo. Se o modelo tivesse:
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']
Então, essa abordagem NÃO funcionaria:
Transaction.objects.values('actor').annotate(total=Count('actor'))
Isso porque o Django executa mais GROUP BY
em cada campo doclass Meta: ordering
Se você imprimir a consulta:
>>> 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"
Ficará claro que a agregação NÃO funcionaria conforme o esperado e, portanto, a .order_by()
cláusula deve ser usada para limpar esse comportamento e obter resultados de agregação adequados.
Veja: Interação com ordenação padrão ou order_by () na documentação oficial do Django.