Al igual que @Alvaro ha respondido el equivalente directo de Django para la GROUP BY
declaración:
SELECT actor, COUNT(*) AS total
FROM Transaction
GROUP BY actor
es mediante el uso de values()
y annotate()
métodos de la siguiente manera:
Transaction.objects.values('actor').annotate(total=Count('actor')).order_by()
Sin embargo, hay que señalar una cosa más:
Si el modelo tiene un orden predeterminado definido en class Meta
, la .order_by()
cláusula es obligatoria para obtener resultados adecuados. Simplemente no puede omitirlo incluso cuando no se pretende realizar un pedido.
Además, para un código de alta calidad, se recomienda colocar siempre una .order_by()
cláusula después annotate()
, incluso cuando no hay class Meta: ordering
. Dicho enfoque hará que la declaración esté preparada para el futuro: funcionará tal como se pretendía, independientemente de cualquier cambio futuro en class Meta: ordering
.
Déjame darte un ejemplo. Si el modelo tuviera:
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']
Entonces tal enfoque NO funcionaría:
Transaction.objects.values('actor').annotate(total=Count('actor'))
Eso es porque Django realiza más GROUP BY
en cada campo enclass Meta: ordering
Si imprime la consulta:
>>> print Transaction.objects.values(
SELECT "Transaction"."actor_id", COUNT("Transaction"."actor_id") AS "total"
FROM "Transaction"
GROUP BY "Transaction"."actor_id", "Transaction"."id"
Quedará claro que la agregación NO funcionaría según lo previsto y, por lo tanto, la .order_by()
cláusula debe usarse para borrar este comportamiento y obtener los resultados de agregación adecuados.
Ver: Interacción con el orden predeterminado o order_by () en la documentación oficial de Django.