Tout comme @Alvaro a répondu à l'équivalent direct de Django pour la GROUP BY
déclaration:
SELECT actor, COUNT(*) AS total
FROM Transaction
GROUP BY actor
se fait par l'utilisation de values()
et des annotate()
méthodes suivantes:
Transaction.objects.values('actor').annotate(total=Count('actor')).order_by()
Cependant, une dernière chose doit être soulignée:
Si le modèle a un ordre par défaut défini dans class Meta
, la .order_by()
clause est obligatoire pour des résultats corrects. Vous ne pouvez tout simplement pas l'ignorer même si aucune commande n'est prévue.
De plus, pour un code de haute qualité, il est conseillé de toujours mettre une .order_by()
clause après annotate()
, même s'il n'y en a pas class Meta: ordering
. Une telle approche rendra la déclaration à l'épreuve du temps: elle fonctionnera comme prévu, indépendamment des modifications futures apportées à class Meta: ordering
.
Laissez-moi vous donner un exemple. Si le modèle avait:
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']
Alors une telle approche NE fonctionnera PAS:
Transaction.objects.values('actor').annotate(total=Count('actor'))
C'est parce que Django effectue des performances supplémentaires GROUP BY
sur chaque champ declass Meta: ordering
Si vous imprimez la requête:
>>> 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"
Il sera clair que l'agrégation ne fonctionnera PAS comme prévu et par conséquent, la .order_by()
clause doit être utilisée pour effacer ce comportement et obtenir des résultats d'agrégation appropriés.
Voir: Interaction avec la commande par défaut ou order_by () dans la documentation officielle de Django.