Unterschied zwischen Djangos Annotations- und Aggregatmethoden?

112

Django QuerySethat zwei Methoden, annotateund aggregate. Die Dokumentation sagt, dass:

Im Gegensatz zu aggregat () ist annotate () keine Terminalklausel. Die Ausgabe der annotate () -Klausel ist ein QuerySet.

Gibt es einen anderen Unterschied zwischen ihnen? Wenn nicht, warum aggregateexistiert es dann?

Alexander Artemenko
quelle

Antworten:

186

Ich würde mich eher auf die Beispielabfragen als auf Ihr Zitat aus der Dokumentation konzentrieren. Aggregateberechnet Werte für den gesamten Abfragesatz. Annotateberechnet zusammenfassende Werte für jedes Element im Abfragesatz.

Anhäufung

>>> Book.objects.aggregate(average_price=Avg('price'))
{'average_price': 34.35}

Gibt ein Wörterbuch zurück, das den Durchschnittspreis aller Bücher im Abfragesatz enthält.

Anmerkung

>>> q = Book.objects.annotate(num_authors=Count('authors'))
>>> q[0].num_authors
2
>>> q[1].num_authors
1

q ist die Abfragemenge der Bücher, aber jedes Buch wurde mit der Anzahl der Autoren versehen.

Alasdair
quelle
Stimmt es, dass .annotate()auf einem qs allein die Datenbank nicht getroffen wird, aber das Aufrufen q[0].num_authors? Ich nehme an aggregatemuss immer die db treffen da es sich um eine terminalklausel handelt?
alias51
@ alias51, das wirklich mit der ursprünglichen Frage zusammenhängt, daher denke ich nicht, dass die Kommentare zu einer acht Jahre alten Frage der beste Ort sind, um sie zu stellen. Wenn Sie überprüfen möchten, wann die Abfragen ausgeführt werden, können Sie dies überprüfenconnection.queries . Hinweis: Überprüfen Sie, ob book = q[0]die Abfrage durch "oder" book.num_authors "verursacht wird.
Alasdair vor
21

Das ist der Hauptunterschied, aber Aggregate funktionieren auch in größerem Maßstab als Anmerkungen. Anmerkungen beziehen sich inhärent auf einzelne Elemente in einem Abfragesatz. Wenn Sie eine CountAnnotation für ein Feld mit vielen zu vielen ausführen, erhalten Sie für jedes Mitglied des Abfragesatzes eine separate Anzahl (als zusätzliches Attribut). Wenn Sie jedoch dasselbe mit einer Aggregation tun würden, würde versucht, jede Beziehung auf jedem Mitglied des Abfragesatzes zu zählen, sogar Duplikate, und diese als nur einen Wert zurückzugeben.

Chris Pratt
quelle
Stimmt es, dass .annotate()auf einem qs allein nicht die Datenbank getroffen wird, sondern das Ergebnis einer Annotation wie q[0].num_authorsfolgt aufgerufen wird? Ich nehme an aggregatemuss immer die db treffen da es sich um eine terminalklausel handelt?
alias51
21

Aggregat Aggregat generiert Ergebniswerte (Zusammenfassung) über ein gesamtes QuerySet. Aggregate arbeiten über das Rowset, um einen einzelnen Wert aus dem Rowset zu erhalten (z. B. Summe aller Preise im Rowset). Das Aggregat wird auf das gesamte QuerySet angewendet und generiert Ergebniswerte (Zusammenfassung) über das gesamte QuerySet.

Im Modell:

class Books(models.Model):
    name = models.CharField(max_length=100)
    pages = models.IntegerField()
    price = models.DecimalField(max_digits=5, decimal_places=3)

In Shell:

>>> Books.objects.all().aggregate(Avg('price'))
# Above code will give the Average of the price Column 
>>> {'price__avg': 34.35}

Annotate Annotate generiert eine unabhängige Zusammenfassung für jedes Objekt in einem QuerySet. (Wir können sagen, dass jedes Objekt in einem QuerySet iteriert und eine Operation angewendet wird.)

Im Modell:

class Video(models.Model):
    name = models.CharField(max_length=52, verbose_name='Name')
    video = models.FileField(upload_to=document_path, verbose_name='Upload 
               video')
    created_by = models.ForeignKey(User, verbose_name='Created by', 
                       related_name="create_%(class)s")
    user_likes = models.ManyToManyField(UserProfile, null=True, 
                  blank=True, help_text='User can like once', 
                         verbose_name='Like by')

Im Hinblick auf:

videos = Video.objects.values('id', 'name','video').annotate(Count('user_likes',distinct=True)

In der Ansicht werden die Likes für jedes Video gezählt

Vinay Kumar
quelle
Warum distinct=Trueist im letzten Beispiel erforderlich?
Yuriy Leonov
@YuriyLeonov unique = True wird verwendet, damit die Operation einen bestimmten Wert ausführt. Es hat nichts mit der aktuell gestellten Frage zu tun. Entschuldigung dafür Eigentlich habe ich meinen Code verwendet.
Vinay Kumar