Genau wie @Alvaro das direkte Äquivalent des Django zur GROUP BY
Aussage beantwortet hat :
SELECT actor, COUNT(*) AS total
FROM Transaction
GROUP BY actor
ist durch die Verwendung von values()
und annotate()
Methoden wie folgt:
Transaction.objects.values('actor').annotate(total=Count('actor')).order_by()
Es muss jedoch noch eines hervorgehoben werden:
Wenn für das Modell eine Standardreihenfolge definiert ist class Meta
, ist die .order_by()
Klausel für ordnungsgemäße Ergebnisse obligatorisch. Sie können es einfach nicht überspringen, auch wenn keine Bestellung beabsichtigt ist.
Für einen qualitativ hochwertigen Code wird außerdem empfohlen, immer eine .order_by()
Klausel nachzusetzen annotate()
, auch wenn keine vorhanden ist class Meta: ordering
. Ein solcher Ansatz macht die Aussage zukunftssicher: Sie funktioniert wie beabsichtigt, unabhängig von zukünftigen Änderungen an class Meta: ordering
.
Lassen Sie mich Ihnen ein Beispiel geben. Wenn das Modell hätte:
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']
Dann würde ein solcher Ansatz NICHT funktionieren:
Transaction.objects.values('actor').annotate(total=Count('actor'))
Das liegt daran, dass Django GROUP BY
auf jedem Feld in zusätzlich zusätzliche Leistungen erbringtclass Meta: ordering
Wenn Sie die Abfrage drucken würden:
>>> 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"
Es ist klar, dass die Aggregation NICHT wie beabsichtigt funktionieren würde, und daher .order_by()
muss die Klausel verwendet werden, um dieses Verhalten zu löschen und korrekte Aggregationsergebnisse zu erhalten.
Siehe: Interaktion mit Standardbestellung oder order_by () in der offiziellen Django-Dokumentation.