Proprio come @Alvaro ha risposto all'equivalente diretto di Django per la GROUP BY
dichiarazione:
SELECT actor, COUNT(*) AS total
FROM Transaction
GROUP BY actor
è attraverso l'uso di values()
e annotate()
metodi come segue:
Transaction.objects.values('actor').annotate(total=Count('actor')).order_by()
Tuttavia un'ultima cosa deve essere sottolineata:
Se il modello ha un ordinamento predefinito definito in class Meta
, la .order_by()
clausola è obbligatoria per risultati corretti. Non puoi saltarlo nemmeno quando non è previsto alcun ordine.
Inoltre, per un codice di alta qualità si consiglia di inserire sempre una .order_by()
clausola dopo annotate()
, anche quando non c'è class Meta: ordering
. Tale approccio renderà la dichiarazione a prova di futuro: funzionerà esattamente come previsto, indipendentemente da eventuali modifiche future a class Meta: ordering
.
Lascia che ti fornisca un esempio. Se il modello avesse:
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']
Allora tale approccio NON FUNZIONERÀ:
Transaction.objects.values('actor').annotate(total=Count('actor'))
Questo perché Django si esibisce in più GROUP BY
su ogni campo inclass Meta: ordering
Se vuoi stampare la query:
>>> 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"
Sarà chiaro che l'aggregazione NON funzionerà come previsto e quindi la .order_by()
clausola deve essere utilizzata per cancellare questo comportamento e ottenere risultati di aggregazione appropriati.
Vedi: Interazione con l'ordinamento predefinito o order_by () nella documentazione ufficiale di Django.