Каковы различия между методами annotate и aggregate в Django ORM

Ответ

В Django ORM annotate() и aggregate() — это методы QuerySet для выполнения агрегатных функций (таких как Sum, Count, Avg), но они возвращают результаты принципиально разного типа.

annotate() — для каждой записи

  • Что делает: Добавляет вычисляемое поле к каждому объекту в QuerySet.
  • Что возвращает: Новый QuerySet, где каждый объект дополнен новым полем.
  • Аналогия: Добавление нового столбца в таблицу с вычисленным значением для каждой строки (например, «количество заказов у каждого клиента»).

aggregate() — для всего набора

  • Что делает: Вычисляет итоговое значение для всего QuerySet.
  • Что возвращает: Словарь (dict) с итоговыми значениями.
  • Аналогия: Вычисление итоговой суммы или среднего по всему столбцу таблицы (например, «общая сумма всех заказов»).

Практический пример

Предположим, у нас есть модели Author и Book:

from django.db import models
from django.db.models import Count, Avg

class Author(models.Model):
    name = models.CharField(max_length=100)

class Book(models.Model):
    title = models.CharField(max_length=100)
    author = models.ForeignKey(Author, on_delete=models.CASCADE, related_name='books')
    rating = models.FloatField()

Использование annotate(): Получим количество книг для каждого автора.

# Возвращает QuerySet объектов Author, у каждого из которых есть поле 'num_books'
authors = Author.objects.annotate(num_books=Count('books'))

for author in authors:
    # author.name = 'J.K. Rowling', author.num_books = 7
    # author.name = 'J.R.R. Tolkien', author.num_books = 3
    print(f"{author.name} написал(а) книг: {author.num_books}")

Использование aggregate(): Вычислим средний рейтинг по всем книгам в базе данных.

# Возвращает словарь с одним ключом 'avg_rating'
result = Book.objects.aggregate(avg_rating=Avg('rating'))

# result будет {'avg_rating': 4.25}
print(f"Средний рейтинг всех книг: {result['avg_rating']}")

Вывод: annotate() обогащает каждую запись в наборе данных, а aggregate() сводит весь набор данных к одному итоговому значению.