Подтвердить что ты не робот

Разница между аннотатами Django и совокупными методами?

Django QuerySet имеет два метода: annotate и aggregate. В документации указано, что:

В отличие от aggregate(), annotate() не является терминальным предложением. Результатом предложения annotate() является QuerySet.

Есть ли другая разница между ними? Если нет, то почему существует aggregate?

4b9b3361

Ответ 1

Я хотел бы сосредоточиться на примерах запросов, а не на цитатах из документации. 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 - это набор запросов к книгам, но каждая книга была аннотирована количеством авторов.

Ответ 2

Это основное отличие, но агрегаты также работают в более масштабном масштабе, чем аннотации. Аннотации по своей сути связаны с отдельными элементами в наборе запросов. Если вы запустите аннотацию Count для поля типа "много-ко-многим", вы получите отдельный счетчик для каждого члена набора запросов (в качестве добавленного атрибута). Однако, если вы должны были сделать то же самое с агрегацией, он попытался бы подсчитать каждую взаимосвязь для каждого члена набора запросов, даже дубликатов, и вернуть это как только одно значение.

Ответ 3

Давайте посмотрим в примере:

class Country(models.Model):
    name = models.CharField(max_length=30)

class City(models.Model):
    name = models.CharField(max_length=30)
    country = models.ForeignKey(Country)
    population = models.PositiveIntegerField()

И исходные данные, хранящиеся в базе данных:

города

id  name    country_id    population
1   Brazil     28         36,923,000
2   Turkey     13         34,000,000
3   Italy      19         30,000,000
4   Seoul      21         25,514,000

страны

id  name
1   Brazil
2   Turkey
3   Italy
4   Seoul

Если бы мы хотели знать общее количество жителей во всех городах, мы могли бы использовать общий запрос:

from django.db.models import Sum

City.objects.aggregate(Sum('population'))
{'population__sum': 126437000}  

Или среднее население в городах:

from django.db.models import Avg

City.objects.aggregate(Avg('population'))
{'population__avg': 31609250} 

Что, если мы сейчас хотим видеть общую численность населения, а не агрегироваться по стране? Не весь набор данных. В этом случае мы больше не можем использовать агрегат, вместо этого будем использовать аннотацию.

City.objects.values('country__name').annotate(Sum('population'))

[
  {'country__name': u'Brazil', 'population__sum': 36,923,000},
  {'country__name': u'Turkey', 'population__sum': 34,000,000},
  {'country__name': u'Italy', 'population__sum': 30,000,000},
  {'country__name': u'Seoul', 'population__sum': 25,514,000},
]

Отказ

для более подробной информации: Django queryset (агрегировать и аннотировать)

Надеюсь, вы нашли этот ответ полезным!

Ответ 4

Совокупный Совокупность генерирует итоговые (итоговые) значения по всему 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)

В оболочке:

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

`

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

In view

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

` ** В виду, что он будет считать понравившиеся для каждого видео, **