Differenza tra i metodi di annotazione e aggregazione di Django?


113

Django QuerySetha due metodi annotatee aggregate. La documentazione dice che:

A differenza di aggregate (), annotate () non è una clausola terminale. L'output della clausola annotate () è un QuerySet.

C'è qualche altra differenza tra loro? In caso contrario, perché aggregateesiste?

Risposte:


186

Mi concentrerei sulle domande di esempio piuttosto che sulla tua citazione dalla documentazione. Aggregatecalcola i valori per l' intero set di query. Annotatecalcola i valori di riepilogo per ogni elemento nel set di query.

Aggregazione

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

Restituisce un dizionario contenente il prezzo medio di tutti i libri nel set di query.

Annotazione

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

q è il set di query di libri, ma ogni libro è stato annotato con il numero di autori.


Ho corretto che .annotate()su un qs da solo non colpisce il db, ma chiamando q[0].num_authorssì? Presumo aggregatedebba sempre premere il db in quanto è una clausola terminale?
alias51

@ alias51 che è davvero correlato alla domanda originale, quindi non penso che i commenti su una domanda di otto anni siano il posto migliore per chiedere. Se vuoi controllare quando vengono eseguite le query, puoi controllareconnection.queries . Suggerimento: controlla se è il book = q[0]o `book.num_authors` che causa la query.
Alasdair

21

Questa è la differenza principale, ma gli aggregati funzionano anche su una scala più ampia rispetto alle annotazioni. Le annotazioni sono intrinsecamente correlate ai singoli elementi in un set di query. Se esegui Countun'annotazione su qualcosa come un campo molti-a-molti, otterrai un conteggio separato per ciascun membro del set di query (come attributo aggiunto). Se si dovesse fare lo stesso con un'aggregazione, tuttavia, si tenterebbe di contare ogni relazione su ogni membro del set di query, anche i duplicati, e di restituirlo come un solo valore.


Ho corretto che .annotate()su un qs da solo non colpisce il db, ma chiamando il risultato di un'annotazione come q[0].num_authorsfa? Presumo aggregatedebba sempre premere il db in quanto è una clausola terminale?
alias51

21

Aggregate Aggregate genera valori di risultato (riepilogo) su un intero QuerySet. L'aggregazione opera sul set di righe per ottenere un singolo valore dal set di righe (ad esempio la somma di tutti i prezzi nel set di righe). Aggregate viene applicato all'intero QuerySet e genera valori di risultato (riepilogo) su un intero QuerySet.

Nel modello:

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

Nel guscio:

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

Annotate Annotate genera un riepilogo indipendente per ogni oggetto in un QuerySet (possiamo dire che itera ogni oggetto in un QuerySet e applica l'operazione)

Nel modello:

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')

In vista:

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

In vista conterà i Mi piace per ogni video


perché distinct=Trueè richiesto nell'ultimo esempio?
Yuriy Leonov

@YuriyLeonov separate = True utilizzato per eseguire l'operazione su un valore distinto. Non è correlato alla domanda corrente posta. Mi dispiace per quello In realtà ho usato sul mio codice.
Vinay Kumar
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.