Різниця між анотацією та сукупністю методів Джанго?


114

У Джанго QuerySetє два способи annotateта aggregate. У документації сказано, що:

На відміну від agregate (), annotate () не є термінальним пунктом. Виведенням статті annotate () є QuerySet.

Чи є якась інша різниця між ними? Якщо ні, то чому це aggregateіснує?

Відповіді:


186

Я б зосередився на прикладних запитах, а не на вашій цитаті з документації. Aggregateобчислює значення для всього набору запитів. Annotateобчислює підсумкові значення для кожного елемента набору запитів.

Агрегація

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

Повертає словник, що містить середню ціну всіх книг у наборі запитів.

Анотація

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

q - це запит книг, але кожну книгу було позначено кількістю авторів.


Чи я правда, що .annotate()лише в qs не потрапляє на db, але дзвінок q[0].num_authorsробить? Я припускаю, що aggregateзавжди повинен потрапляти на db, оскільки це термінальна пропозиція?
alias51

@ alias51, що насправді пов'язане з оригінальним запитанням, тому я не думаю, що коментарі до восьмирічного питання є найкращим місцем для запитання. Якщо ви хочете перевірити, коли запити виконуються, тоді ви можете перевіритиconnection.queries . Підказка: перевірте, чи book = q[0]викликає запит це чи book.num_authors.
Alasdair

21

У цьому головна відмінність, але агрегати також працюють в масштабніших масштабах, ніж анотації. Анотації суттєво пов'язані з окремими елементами в наборі запитів. Якщо запустити Countанотацію на щось схоже на поле "багато-багато", ви отримаєте окремий підрахунок для кожного члена набору запитів (як доданий атрибут). Якщо ви зробили те ж саме з агрегуванням, воно намагатиметься порахувати кожне відношення кожного члена набору запитів, навіть дублікати, і поверне це як лише одне значення.


Чи я правда, що .annotate()лише в qs не потрапляє на db, але викликає результат примітки, як q[0].num_authors, наприклад,? Я припускаю, що aggregateзавжди повинен потрапляти на db, оскільки це термінальна пропозиція?
alias51

21

Сукупне агрегування генерує значення результату (підсумки) протягом усього QuerySet. Сукупність працює над набором рядків, щоб отримати одне значення з набору рядків (наприклад, сума всіх цін у наборі рядків). Агрегат застосовується до всього QuerySet, і він генерує результати (підсумки) значення для цілого QuerySet.

У моделі:

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

В Shell:

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

Annotate Annotate генерує незалежний підсумок для кожного об'єкта в QuerySet. (Ми можемо сказати, що це повторює кожен об'єкт у QuerySet та застосовує операцію)

У моделі:

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

Перегляд:

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

У перегляді він підраховує лайки до кожного відео


чому distinct=Trueце потрібно в останньому прикладі?
Юрій Леонов

@YuriyLeonov razloct = Встановлено, що для цієї операції виконується окреме значення. Це не пов’язано з поточним заданим питанням. Вибачте за те, що насправді я використав свій код.
Вінай Кумар
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.