Perbedaan antara metode anotasi dan agregat Django?

113

Django QuerySetmemiliki dua metode, annotatedan aggregate. Dokumentasi mengatakan bahwa:

Tidak seperti aggregate (), annotate () bukanlah klausa terminal. Output dari klausa annotate () adalah QuerySet.

Apakah ada perbedaan lain di antara keduanya? Jika tidak, lalu mengapa aggregateada?

Alexander Artemenko
sumber

Jawaban:

186

Saya akan fokus pada permintaan contoh daripada kutipan Anda dari dokumentasi. Aggregatemenghitung nilai untuk seluruh queryset. Annotatemenghitung nilai ringkasan untuk setiap item di queryset.

Pengumpulan

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

Menampilkan kamus yang berisi harga rata-rata semua buku di queryset.

Anotasi

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

q adalah queryset buku, tetapi setiap buku telah diberi keterangan jumlah penulisnya.

Alasdair
sumber
Apakah saya benar bahwa .annotate()pada qs saja tidak mengenai db, tetapi pemanggilan q[0].num_authorstidak? Saya berasumsi aggregateharus selalu menekan db karena itu adalah klausa terminal?
alias51
@ alias51 itu benar-benar terkait dengan pertanyaan awal, jadi menurut saya komentar pada pertanyaan berusia delapan tahun adalah tempat terbaik untuk bertanya. Jika Anda ingin memeriksa kapan kueri dijalankan, maka Anda dapat memeriksaconnection.queries . Petunjuk: periksa apakah book = q[0]atau `book.num_authors` yang menyebabkan kueri.
Alasdair
21

Itulah perbedaan utamanya, tetapi agregat juga bekerja dalam skala yang lebih besar daripada anotasi. Anotasi secara inheren terkait dengan item individual dalam queryset. Jika Anda menjalankan Countanotasi pada sesuatu seperti bidang banyak-ke-banyak, Anda akan mendapatkan jumlah terpisah untuk setiap anggota set kueri (sebagai atribut tambahan). Jika Anda melakukan hal yang sama dengan agregasi, bagaimanapun, itu akan mencoba menghitung setiap hubungan pada setiap anggota queryset, bahkan duplikat, dan mengembalikannya hanya sebagai satu nilai.

Chris Pratt
sumber
Apakah saya benar bahwa .annotate()pada qs saja tidak mengenai db, tetapi memanggil hasil anotasi seperti q[0].num_authorsitu? Saya berasumsi aggregateharus selalu menekan db karena itu adalah klausa terminal?
alias51
21

Agregat Agregat menghasilkan nilai hasil (ringkasan) di seluruh QuerySet. Agregat beroperasi melalui kumpulan baris untuk mendapatkan nilai tunggal dari kumpulan baris. (Misalnya jumlah semua harga di kumpulan baris). Agregat diterapkan di seluruh QuerySet dan menghasilkan nilai hasil (ringkasan) di seluruh QuerySet.

Dalam Model:

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

Di Shell:

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

Annotate Annotate menghasilkan ringkasan independen untuk setiap objek dalam QuerySet. (Kita dapat mengatakan iterasi setiap objek dalam QuerySet dan menerapkan operasi)

Dalam Model:

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

Dalam penglihatan:

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

Dalam tampilan ini akan menghitung suka untuk setiap video

Vinay Kumar
sumber
mengapa distinct=Truediperlukan dalam contoh terakhir?
Yuriy Leonov
@YuriyLeonov different = True yang digunakan untuk menjalankan operasi pada nilai yang berbeda. Ini tidak terkait dengan pertanyaan saat ini yang diajukan. Maaf untuk itu Sebenarnya saya telah menggunakan kode saya.
Vinay Kumar