Перш ніж ми зануримось у код, давайте розберемось із теорією. Агрегації в контексті роботи з даними — це процеси, які дозволяють нам "стиснути" дані для отримання узагальнених результатів. Якщо ми хочемо дізнатися, скільки у нас користувачів, яка середня ціна товарів в інтернет-магазині або скільки завдань виконано, агрегації стануть вашими друзями.
У SQL це функції, такі як COUNT, SUM, AVG, MAX, MIN. Django ORM пропонує зручну можливість використовувати їх, не втрачаючи магії Python.
Навіщо потрібні агрегації?
Уявіть, ви на складі, а там — тисячі коробок. Вам потрібно підрахувати загальну кількість коробок червоного кольору. Замість того щоб вручну перераховувати коробки і записувати результати (або виконувати кілька запитів до бази), ви просто агрегуєте дані. Це не тільки економить час, але й покращує продуктивність роботи з базою даних.
Простий приклад агрегації
Давай почнемо з базового прикладу. У нас є модель Product, яка представляє товари в інтернет-магазині.
from django.db import models
class Product(models.Model):
name = models.CharField(max_length=100)
price = models.DecimalField(max_digits=10, decimal_places=2)
quantity = models.IntegerField()
Припустимо, база даних вже заповнена декількома товарами. Нам потрібно знайти, скільки всього товарів на складі.
У Django ORM це виглядає ось так:
from django.db.models import Sum
total_quantity = Product.objects.aggregate(Sum('quantity'))
print(total_quantity)
# Виведе: {'quantity__sum': 150} (наприклад)
Що ми бачимо в коді?
- Ми викликали метод
.aggregate()на QuerySet. - Всередині
.aggregate()ми використали функціюSum, щоб підрахувати загальну кількість. - Результат повертається у вигляді словника, де ключ — це ім'я поля (
quantity__sumза замовчуванням).
І все! Ми зробили наш перший агрегатний запит. Круто, чи не так?
Як працює функція .aggregate()
Щоб краще зрозуміти, як працює метод .aggregate(), давайте розберемо процес крок за кроком.
.aggregate()виконує один запит до бази даних і повертає один рядок із результатами.- Він не повертає об'єкти моделі, а одразу видає обчислені значення.
- Ви можете комбінувати декілька агрегатних функцій в одному запиті.
Приклад із декількома агрегатними функціями:
from django.db.models import Sum, Avg
result = Product.objects.aggregate(
total_quantity=Sum('quantity'),
average_price=Avg('price')
)
print(result)
# Виведе: {'total_quantity': 150, 'average_price': Decimal('25.30')}
Зверніть увагу на те, що для зручності ми вказали кастомні ключі (total_quantity, average_price), щоб їхні значення було простіше використовувати.
Чому .aggregate() краще, ніж звичайний Python?
У тебе може виникнути питання: "Навіщо використовувати .aggregate()? Хіба не можна просто дістати всі дані і порахувати їх у Python?"
Відповідь коротка: можна, але не потрібно. Причина в тому, що .aggregate() дозволяє перенести обчислення на рівень бази даних, що економніше. База даних оптимізована для таких операцій, тому така реалізація буде швидшою і менш ресурсозатратною.
Приклад неправильного підходу:
total_quantity = sum(product.quantity for product in Product.objects.all())
Цей код:
- Дістає всі записи з бази даних, що може бути дуже повільно, якщо даних багато.
- Виконує обчислення у Python, перевантажуючи твою пам'ять.
Приклад правильного підходу, як ми вже бачили раніше:
total_quantity = Product.objects.aggregate(Sum('quantity'))
Цей запит виконується лише на рівні бази даних і повертає результат одразу. Швидко, зручно та елегантно!
Основні сценарії використання агрегацій
Давайте розглянемо, де можна застосовувати агрегації у реальних додатках:
Інтернет-магазини:
- Порахувати загальну кількість продажів.
- Порахувати загальну суму покупок.
Соціальні мережі:
- Кількість лайків під постами.
- Середня кількість коментарів на пост.
Робота з користувачами:
- Кількість активних користувачів.
- Середній вік користувачів.
Приклад для підрахунку кількості активних користувачів:
from django.db.models import Count
active_users = User.objects.filter(is_active=True).aggregate(Count('id'))
print(active_users)
# Виведе: {'id__count': 42}
Помилки при використанні .aggregate()
Звісно, шлях програміста всіяний граблями. Ось кілька з них — типові помилки:
Забули викликати
.filter()перед.aggregate()Якщо ви хочете агрегувати дані тільки для певної групи записів, не забудьте додати фільтр:total_sales = Product.objects.filter(is_sold=True).aggregate(Sum('quantity'))Якщо ви забудете
.filter(), то буде агреговано все, а не тільки очікувані записи.Спроба використовувати
.aggregate()після.all()Пам’ятайте,.aggregate()викликається на QuerySet одразу, а не після.all(). Інакше буде помилка.Неявне використання імен полів За замовчуванням
Djangoдодає__sum,__avgта інше до імен полів. Тому, якщо ви хочете використовувати конкретний ключ, вкажіть його явно:result = Product.objects.aggregate(total=Sum('quantity')) print(result['total']) # Так простіше!
Практичне завдання
Самостійно напишіть агрегатний запит у вашій поточній навчальній моделі (або створіть нову модель). Ось кілька ідей:
- Підрахуйте загальну кількість записів у моделі.
- Знайдіть максимальну ціну товару.
- Обчисліть середню кількість чого-небудь.
Приклад:
from django.db.models import Max
max_price = Product.objects.aggregate(Max('price'))
print(max_price)
# Наприклад: {'price__max': Decimal('100.00')}
Що далі?
Тепер, коли ви розумієте основи агрегацій і вмієте використовувати .aggregate(), ви готові до більш складних технік: анотацій, складних фільтрацій і використання Q-об'єктів. Ми продовжимо вивчення цих тем у наступних лекціях.
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ