Ich verwende ein Transaktionsmodell, um alle Ereignisse im System zu verfolgen
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()
......
Wie bekomme ich die Top 5 Schauspieler in meinem System?
In SQL wird es im Grunde sein
SELECT actor, COUNT(*) as total
FROM Transaction
GROUP BY actor
ORDER BY total DESC
django
django-queryset
totoromeow
quelle
quelle
Antworten:
Gemäß der Dokumentation sollten Sie verwenden:
values (): Gibt an, welche Spalten zum "Gruppieren nach" verwendet werden sollen.
Django docs:
annotate (): Gibt eine Operation über die gruppierten Werte an
Django docs:
Die Reihenfolge nach Klausel ist selbsterklärend.
Zusammenfassend: Sie gruppieren nach, generieren eine Abfragemenge von Autoren, fügen die Anmerkung hinzu (dies fügt den zurückgegebenen Werten ein zusätzliches Feld hinzu) und ordnen sie schließlich nach diesem Wert
Siehe https://docs.djangoproject.com/de/dev/topics/db/aggregation/Weitere
Gut zu beachten: Wenn Sie Count verwenden, wirkt sich der an Count übergebene Wert nicht auf die Aggregation aus, sondern nur auf den Namen des endgültigen Werts. Der Aggregator gruppiert nach eindeutigen Kombinationen der Werte (wie oben erwähnt) und nicht nach dem an Count übergebenen Wert. Folgende Abfragen sind gleich:
quelle
Transaction.objects.all().values('actor').annotate(total=Count('actor')).order_by('total')
, vergessen Sie nicht, Count aus django.db.models zu importieren. Vielen DankCount
(und möglicherweise andere Aggregatoren) verwenden,Count
wirkt sich der übergebene Wert nicht auf die Aggregation aus, sondern nur auf den Namen des endgültigen Werts. Der Aggregator gruppiert nach eindeutigen Kombinationen dervalues
(wie oben erwähnt), nicht nach dem an übergebenen WertCount
.total
ist der Name angegeben und die Anzahl in SQL verwendet,COUNT('actor')
was in diesem Fall keine Rolle spielt, aber wenn Sie zBvalues('x', 'y').annotate(count=Count('x'))
erhaltenCOUNT(x)
, nichtCOUNT(*)
oderCOUNT(x, y)
, versuchen Sie es einfach in./manage.py shell
Genau wie @Alvaro das direkte Äquivalent des Django zur
GROUP BY
Aussage beantwortet hat :ist durch die Verwendung von
values()
undannotate()
Methoden wie folgt: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 nachzusetzenannotate()
, auch wenn keine vorhanden istclass Meta: ordering
. Ein solcher Ansatz macht die Aussage zukunftssicher: Sie funktioniert wie beabsichtigt, unabhängig von zukünftigen Änderungen anclass Meta: ordering
.Lassen Sie mich Ihnen ein Beispiel geben. Wenn das Modell hätte:
Dann würde ein solcher Ansatz NICHT funktionieren:
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:
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.
quelle
.order_by()
hat michordering
in Meta gerettet .