JavaRush /Курси /Модуль 3: Django /Використання функції `aggregate()` в Django ORM

Використання функції `aggregate()` в Django ORM

Модуль 3: Django
Рівень 10 , Лекція 1
Відкрита

Давай поговоримо про функцію aggregate(), яка дозволяє збирати дані та обчислювати агрегатні показники. Це найважливіший інструмент для аналітичних запитів, і, як кажуть, "рахувати гроші потрібно не тільки в банку, але й у базі даних".

🎯 Навіщо потрібен метод aggregate()?

Коли ти працюєш з даними, бувають ситуації, коли потрібно не просто отримати список об'єктів, а обчислити щось сумарне або узагальнене. Наприклад:

  • Скільки користувачів зареєструвалися на сайті?
  • Який середній вік клієнтів нашого магазину?
  • Яка максимальна сума замовлення?

Замість того, щоб витягувати всі записи і обробляти їх у Python, aggregate() дозволяє виконати ці обчислення на стороні бази даних. Це швидше, ефективніше і, найголовніше, зменшує навантаження на сервер.

🔧 Основи використання функції aggregate()

Функція aggregate() використовується на рівні QuerySet і повертає словник, де ключі — це імена полів, а значення — результати обчислень. Ось базовий синтаксис:

from django.db.models import Avg, Count, Max, Min, Sum

queryset.aggregate(AggregateFunction('поле_моделі'))

Давайте розглянемо мінімалістичний приклад з моделлю Order:

# Модель замовлення
class Order(models.Model):
    customer = models.CharField(max_length=100)
    amount = models.DecimalField(max_digits=10, decimal_places=2)  # Сума замовлення
    created_at = models.DateTimeField(auto_now_add=True)

Використовуємо aggregate(), щоб отримати загальну суму всіх замовлень:

from django.db.models import Sum

total_sales = Order.objects.aggregate(Sum('amount'))
print(total_sales)  # Вивід: {'amount__sum': 12345.67}

Зверніть увагу, що результат повертається у вигляді словника. До ключа додається суфікс __sum, щоб вказати тип обчислення.

🛠 Практичне застосування

Щоб розвивати наш приклад, ми додамо кілька функцій для підрахунку статистики. Припустимо, наша БД вже містить дані.

Підрахунок кількості записів з Count

from django.db.models import Count

order_count = Order.objects.aggregate(Count('id'))
print(order_count)  # Вивід: {'id__count': 20}

Тут ми підраховуємо кількість записів у таблиці замовлень. Поле моделі в Count() може бути будь-яким, головне, щоб воно було унікальним.

Середні значення з Avg

Якщо ми хочемо дізнатися середню суму замовлення, використовуємо Avg:

from django.db.models import Avg

average_order = Order.objects.aggregate(Avg('amount'))
print(average_order)  # Вивід: {'amount__avg': 123.45}

Це допоможе зрозуміти, наскільки наші клієнти щедрі (або навпаки).

Максимум і мінімум з Max і Min

Вийдемо на новий рівень аналітики: визначаємо найбільше і найменше замовлення.

from django.db.models import Max, Min

max_min_order = Order.objects.aggregate(Max('amount'), Min('amount'))
print(max_min_order)
# Вивід: {'amount__max': 999.99, 'amount__min': 10.00}

Тут ми одразу використовуємо два агрегатні методи, щоб отримати максимальне і мінімальне значення.

🤔 Порівняння aggregate() і annotate()

На цьому етапі важливо зрозуміти, чим aggregate() відрізняється від annotate().

  • aggregate() повертає ОДНЕ значення (або кілька значень у словнику) для всього QuerySet. Це "підсумкове" обчислення.
  • annotate() додає обчислювані значення до кожного рядка результату. Це "збагачення" даних.

Для прикладу: якщо ми використовуємо annotate() для підрахунку кількості замовлень, результат міститиме окреме поле для кожного користувача.

🚀 Комбінування кількох агрегатів

Функція aggregate() дозволяє комбінувати кілька операцій одразу. Наприклад, порахуємо середню суму, кількість і максимальне замовлення одночасно:

stats = Order.objects.aggregate(
    avg_amount=Avg('amount'),
    total_orders=Count('id'),
    max_amount=Max('amount')
)
print(stats)
# Вивід: {'avg_amount': 123.45, 'total_orders': 20, 'max_amount': 999.99}

Тут ми даємо зрозумілі імена для результатів: avg_amount, total_orders і max_amount.

🐛 Типові помилки при використанні aggregate()

При роботі з aggregate() є кілька поширених помилок, яких слід уникати:

  1. Якщо в базі немає даних, агрегатні функції повернуть None, тому перевіряйте результати:

    result = Order.objects.aggregate(Sum('amount'))
    print(result['amount__sum'] or 0)  # Якщо сума None, повертаємо 0
    
  2. Не забувайте, що при використанні агрегатів поле, яке ви передаєте, має бути коректним. Помилка буде, якщо зробити так:

    # Поля 'amount1' не існує
    stats = Order.objects.aggregate(Sum('amount1'))
    # Помилка! FieldError: Cannot resolve keyword 'amount1'
  3. Агрегати працюють тільки з QuerySet. Якщо ви спробуєте зробити так:

    single_order = Order.objects.first()
    single_order.aggregate(Sum('amount'))  # Помилка! AttributeError: 'Order' object has no attribute 'aggregate'
    

    То отримаєте помилку, оскільки aggregate() застосовується для наборів даних, а не для окремого запису.

🛡 Корисні поради та оптимізація

  1. Не рахуйте вручну! Якщо тобі потрібно порахувати дані, довірся базі даних. Агрегації в Django ORM виконуються на рівні SQL, а значить, вони швидкі та оптимізовані.

  2. Використовуй індекси. Якщо ти часто виконуєш агрегації на одному і тому ж полі, наприклад, Sum('price'), переконайся, що поле проіндексоване в таблиці бази даних. Це пришвидшить запити.

  3. Кешуй результати. Якщо твої дані не змінюються часто, зберігай результати агрегатів у кеші або навіть в окремій таблиці (наприклад, для дашборду).

💡 Завдання для самостійної роботи

Щоб закріпити матеріал, спробуйте в рамках вашого проєкту реалізувати наступні завдання:

  1. Підрахуйте загальну суму замовлень для заданої дати (наприклад, сьогодні).
  2. Знайдіть максимальну та мінімальну суму замовлення серед усіх замовлень.
  3. Визначте, скільки клієнтів зробили хоча б одне замовлення.
  4. Розрахуйте середню суму замовлень для клієнтів, у яких замовлень більше 3.

Таким чином, ви освоїли базу роботи з функцією aggregate(). Цьому інструменту знайдеться застосування у будь-якому аналітичному модулі вашого веб-додатку, будь то звіти, дашборди або користувацька статистика. Без перевантаження сервера, дані будуть "літати" (майже як JavaScript, тільки надійніше 😄). У наступній лекції ми розглянемо анотації та їх застосування — вони дозволять розгорнути ваші аналітичні здібності на максимум.

Коментарі
ЩОБ ПОДИВИТИСЯ ВСІ КОМЕНТАРІ АБО ЗАЛИШИТИ КОМЕНТАР,
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ