Давай заглибимось у вивчення основних агрегатних функцій таких як Sum, Avg і Count. Ці інструменти є базовими цеглинками, які допомагають нам збирати корисну статистику з даних веб-додатку.
Уяви, що у тебе є інтернет-магазин і потрібно дізнатися, скільки всього замовлень оформлено (Count), яка їх середня вартість (Avg) або яка загальна сума всіх замовлень (Sum). Без агрегатних функцій це можна було б зробити вручну:
orders = Order.objects.all()
total_orders = len(orders)
total_sum = sum(order.price for order in orders)
avg_sum = total_sum / total_orders if total_orders > 0 else 0
Красиво? Ну, таке... Ефективно? Не дуже! Django ORM дозволяє делегувати такі задачі базі даних, де ці операції виконуються швидше і з меншими витратами.
Основні агрегатні функції
Давай розбиратися з кожною з основних функцій по черзі. Запасайся чаєм/кавою та гарним настроєм, попереду багато коду!
1. Count: підрахунок записів
Коли ти хочеш дізнатися просто кількість записів у базі даних, на допомогу приходить Count. Це найпростіша і часто використовувана функція.
Приклад:
Почнемо з простого. Припустимо, у нас є модель Order:
# models.py
from django.db import models
class Order(models.Model):
total_price = models.DecimalField(max_digits=10, decimal_places=2)
created_at = models.DateTimeField(auto_now_add=True)
Щоб дізнатися, скільки у нас всього замовлень, використовуємо aggregate() з Count:
from django.db.models import Count
result = Order.objects.aggregate(total_orders=Count('id'))
print(result) # {'total_orders': 42}
Тут 'id' вказує на поле, за яким ми рахуємо записи. Повертається словник, де ключ — це ім'я, яке ти дав своєму агрегату. У цьому випадку це total_orders.
Підрахунок унікальних значень
Іноді хочеться дізнатися, скільки унікальних значень є в якомусь полі. Наприклад, скільки унікальних дат, коли були зроблені замовлення.
unique_dates = Order.objects.aggregate(unique_dates=Count('created_at', distinct=True))
print(unique_dates) # {'unique_dates': 7}
Прапор distinct=True дозволяє ігнорувати дублікатори.
2. Sum: сума значень
Тепер давай підрахуємо загальну суму всіх замовлень. Для цього використовуємо функцію Sum.
Приклад:
from django.db.models import Sum
result = Order.objects.aggregate(total_revenue=Sum('total_price'))
print(result) # {'total_revenue': Decimal('3000.50')}
Зазвичай тобі потрібно буде працювати з числовими типами даних, такими як IntegerField або DecimalField. Sum чудово працює з обома.
У реальних додатках часто треба обчислити суму за якоюсь умовою. Наприклад, суму замовлень, створених у певний день.
from django.utils.timezone import now
today = now().date()
daily_revenue = Order.objects.filter(created_at__date=today).aggregate(total_revenue=Sum('total_price'))
print(daily_revenue) # {'total_revenue': Decimal('500.00')}
Тут ми фільтруємо замовлення перед застосуванням aggregate().
3. Avg: середнє значення
Тепер давай визначимо середню вартість замовлення. Для цього використовуємо функцію Avg.
Приклад:
from django.db.models import Avg
result = Order.objects.aggregate(average_price=Avg('total_price'))
print(result) # {'average_price': Decimal('142.50')}
Середнє значення — це корисна функція, якщо ти хочеш аналізувати тенденції даних. Наприклад, якщо середня вартість замовлення зростає, це може бути індикатором збільшення обсягів продажів.
Порівняння результатів
Давай тепер зберемо все разом. Наприклад, нам потрібно одразу порахувати:
- Загальну кількість замовлень.
- Загальну суму всіх замовлень.
- Середню вартість замовлення.
Ми можемо зробити це одним запитом:
result = Order.objects.aggregate(
total_orders=Count('id'),
total_revenue=Sum('total_price'),
average_price=Avg('total_price')
)
print(result)
# {'total_orders': 42, 'total_revenue': Decimal('3000.50'), 'average_price': Decimal('142.50')}
Це зручно і ефективно: один виклик бази даних для отримання трьох різних метрик.
Практичне завдання
Спробуй самостійно реалізувати наступний сценарій. У тебе є модель Product:
# models.py
class Product(models.Model):
name = models.CharField(max_length=255)
price = models.DecimalField(max_digits=10, decimal_places=2)
stock = models.IntegerField() # кількість на складі
Твої завдання:
- Підрахувати загальну кількість товарів.
- Підрахувати загальну вартість усіх товарів на складі (ціна * кількість на складі).
- Знайти середню ціну товару.
Підказка: для виконання другого завдання тобі знадобиться використання анотацій з annotate() (ми поговоримо про це далі), але ти можеш почати вирішення, використовуючи тільки aggregate().
Типові помилки при роботі з агрегатами
Коли починаєш працювати з агрегатами, можна зіткнутися з кількома нюансами.
Наприклад, якщо ти намагаєшся передати поле, якого немає в моделі, Django викине тобі виключення. Переконайся, що вказане поле існує і правильно написане.
Також, якщо поле, яке використовується для агрегатів, містить NULL значення, база даних може ігнорувати їх при обчисленнях. Якщо ти хочеш включити такі записи, використовуй default для null значень, щоб уникнути неочікуваних результатів.
# Переконайся, що поле total_price завжди числове
Order.objects.aggregate(total_revenue=Sum('total_price', default=0))
Застосування в реальному житті
У реальному житті агрегатні функції активно використовуються для створення звітів, метрик для дашбордів або ж для виконання аналітики прямо у веб-додатку.
Наприклад:
- Підрахунок кількості нових користувачів за тиждень
Count. - Загальна кількість проданих товарів
Sum. - Середній чек за день
Avg.
Це саме ті задачі, які роблять твій додаток корисним для бізнесу.
І останнє: не забувай слідкувати за продуктивністю запитів, особливо якщо працюєш із великими даними. Використовуй можливості бази даних на повну потужність, але пам’ятай, що грамотна індексація та налаштування бази часто рятують від несподіваного зниження продуктивності.
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ