🔖 Справочник: Практикум 6
⚡ Шпаргалка
# Агрегация одного значения
Model.objects.aggregate(alias=Func(F('field')))['alias']
# Группировка + аннотация
Model.objects.values('group_field').annotate(alias=Func('field')).order_by('group_field')
# ExpressionWrapper для вычисления разницы дат
.annotate(lifetime=ExpressionWrapper(F('end') - F('start'), output_field=fields.DurationField()))
# order_by
.order_by('-price') # убывание
.order_by('country', 'city') # несколько полей
.annotate(cnt=Count('items')).order_by('-cnt') # по аннотации
# Временные метки
one_month_ago = timezone.now() - timezone.timedelta(days=30)
Order.objects.filter(order_date__gte=one_month_ago)
# Срезы
Model.objects.all()[:5]
Model.objects.order_by('-price')[:10]
Агрегирующие функции
| Функция | Описание | Импорт |
|---|---|---|
Sum(expr) | Сумма значений | django.db.models |
Avg(expr) | Среднее значение | django.db.models |
Min(expr) | Минимальное значение | django.db.models |
Max(expr) | Максимальное значение | django.db.models |
Count(expr) | Количество объектов/значений | django.db.models |
Паттерны агрегации
# Паттерн 1: aggregate — одно значение
from django.db.models import Sum, F
result = Product.objects.aggregate(
total_value=Sum(F('price') * F('quantity'))
)['total_value']
# Паттерн 2: values + annotate — группировка
from django.db.models import Avg
avg_by_cat = Product.objects.values('category__name').annotate(
average_price=Avg('price')
).order_by('category__name')
# Паттерн 3: Min / Max через aggregate
from django.db.models import Min, Max
extremes = Product.objects.aggregate(
min_price=Min('price'),
max_price=Max('price')
)
# Паттерн 4: Count через annotate
from django.db.models import Count
by_supplier = Product.objects.values('supplier__name').annotate(
product_count=Count('id')
).order_by('supplier__name')
ExpressionWrapper
from django.db.models import Avg, F, ExpressionWrapper, fields
from store.models import ProductDetail
# Вычислить разницу дат как DurationField
avg_lifetime = ProductDetail.objects.annotate(
lifetime=ExpressionWrapper(
F('expiration_date') - F('manufacturing_date'),
output_field=fields.DurationField()
)
).aggregate(average_lifetime=Avg('lifetime'))['average_lifetime']
# Результат — объект timedelta; .days — количество дней
print(avg_lifetime.days)
order_by
# Один критерий, убывание
Product.objects.order_by('-price')
# Несколько критериев
Address.objects.order_by('country', 'city')
# По аннотированному полю
Order.objects.annotate(
total=Sum(F('order_items__price') * F('order_items__quantity'))
).order_by('-total')
Order.objects.annotate(
item_count=Count('order_items')
).order_by('-item_count')
Временные метки
from django.utils import timezone
from store.models import Order
# Один месяц назад
one_month_ago = timezone.now() - timezone.timedelta(days=30)
# Фильтр: дата >= one_month_ago
recent = Order.objects.filter(order_date__gte=one_month_ago)
# Другие временные lookups
Order.objects.filter(order_date__year=2024)
Order.objects.filter(order_date__month=6)
Order.objects.filter(order_date__date=timezone.now().date())
Срезы QuerySet
# Первые N записей
Product.objects.all()[:5]
Product.objects.all()[:10]
# Комбинация с order_by
Product.objects.order_by('-price')[:10] # топ-10 дорогих
# Диапазон [start:stop] — OFFSET + LIMIT
Product.objects.all()[10:20] # с 11-й по 20-ю
После применения среза QuerySet нельзя применять
filter(), order_by() или другие методы, изменяющие запрос. Применяйте срез последним.
Настройка данных (Интро к практикуму)
# В Django shell: загрузить тестовые данные
python manage.py shell
from store_data import *
export_data()