Django'nun açıklama ve toplama yöntemleri arasındaki fark nedir?


115

Django'nun QuerySetiki yöntemi vardır annotateve aggregate. Belgeler şunu söylüyor:

Aggregate () 'den farklı olarak, annotate () bir terminal cümlesi değildir. Annotate () cümlesinin çıktısı bir QuerySet'tir.

Aralarında başka bir fark var mı? Değilse, neden aggregatevar?

Yanıtlar:


188

Dokümantasyondan yaptığınız alıntıdan ziyade örnek sorgulara odaklanırdım. sorgu kümesinin tamamıAggregate için değerleri hesaplar . sorgu kümesindeki her öğe için özet değerleri hesaplar .Annotate

toplanma

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

Sorgu kümesindeki tüm kitapların ortalama fiyatını içeren bir sözlük döndürür .

not

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

q kitapların sorgu kümesidir, ancak her kitap yazarların sayısıyla açıklanmıştır.


.annotate()Bir qs üzerinde tek başına db'yi vurmadığı, ancak aramanın işe yaradığı konusunda doğru muyum q[0].num_authors? aggregateBir terminal cümlesi olduğu için her zaman db'ye basmanız gerektiğini varsayıyorum ?
alias51

@ alias51 orjinal soruyla gerçekten alakalı, bu yüzden sekiz yaşındaki bir sorudaki yorumların sorulacak en iyi yer olduğunu düşünmüyorum. Sorguların ne zaman çalıştığını kontrol etmekconnection.queries istiyorsanız, kontrol edebilirsiniz . İpucu: book = q[0]sorguya neden olan şeyin "book.num_authors" olup olmadığını kontrol edin .
Alasdair

21

Temel fark bu, ancak toplamalar ayrıca ek açıklamalardan daha büyük bir ölçekte çalışır. Ek açıklamalar, doğası gereği bir sorgu kümesindeki tek tek öğelerle ilgilidir. CountÇoktan çoğa alanı gibi bir şey üzerinde bir açıklama çalıştırırsanız , sorgu kümesinin her bir üyesi için ayrı bir sayı alırsınız (ek bir öznitelik olarak). Bununla birlikte, bir toplama ile aynı şeyi yapacak olsaydınız , sorgu kümesinin her üyesindeki her ilişkiyi , hatta kopyaları bile saymaya çalışır ve bunu tek bir değer olarak döndürür.


Bunu haklı mıyım .annotate()bir qs yalnız db vurmak yok, ama gibi bir açıklama sonucunu çağırarak q[0].num_authorsyapar? aggregateBir terminal cümlesi olduğu için her zaman db'ye basmanız gerektiğini varsayıyorum ?
alias51

21

Aggregate Aggregate, tüm bir QuerySet üzerinden sonuç (özet) değerleri üretir. Agrega, satır kümesinden tek bir değer elde etmek için satır kümesi üzerinde çalışır. (Örneğin, satır kümesindeki tüm fiyatların toplamı). Toplama, tüm QuerySet'e uygulanır ve bir QuerySet'in tamamında sonuç (özet) değerleri oluşturur.

Modelde:

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

Kabukta:

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

Annotate Annotate, bir QuerySet'teki her nesne için bağımsız bir özet oluşturur. (Her nesneyi bir QuerySet'te yinelediğini ve işlemi uyguladığını söyleyebiliriz)

Modelde:

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

Görünümünde:

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

Görünümde, her videonun beğenilerini sayacak


distinct=Trueson örnekte neden gerekli?
Yuriy Leonov

@YuriyLeonov farklı = İşlemin farklı bir değerde gerçekleştirilmesi için kullanılan doğru. Sorulan şu anki soruyla ilgili değil. Bunun için üzgünüm Aslında kodumu kullandım.
Vinay Kumar
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.