💻 Примеры: Практикум 6

⚡ Ключевые примеры

# Sum F*F
Product.objects.aggregate(total=Sum(F('price') * F('quantity')))['total']

# Avg + group
Product.objects.values('category__name').annotate(avg=Avg('price'))

# ExpressionWrapper
ProductDetail.objects.annotate(
    lifetime=ExpressionWrapper(F('expiration_date') - F('manufacturing_date'),
    output_field=fields.DurationField())
).aggregate(avg=Avg('lifetime'))['avg'].days

# order_by annotated
Order.objects.annotate(total=Sum(F('order_items__price')*F('order_items__quantity'))).order_by('-total')

# timezone + filter
Order.objects.filter(order_date__gte=timezone.now() - timezone.timedelta(days=30))

# Срез
Product.objects.order_by('-price')[:10]

Пример 1: Общая стоимость через Sum(F*F)

Перемножаем два поля на уровне SQL и суммируем:

from django.db.models import Sum, F
from store.models import Product

total_value = Product.objects.aggregate(
    total_value=Sum(F('price') * F('quantity'))
)['total_value']

print(f"Общая стоимость всех продуктов: {total_value}")
# Общая стоимость всех продуктов: 158432.50

Пример 2: Группировка + Avg по категориям

Паттерн values().annotate() — аналог SQL GROUP BY:

from django.db.models import Avg
from store.models import Product

average_price_by_category = Product.objects.values('category__name').annotate(
    average_price=Avg('price')
).order_by('category__name')

for entry in average_price_by_category:
    print(f"Категория: {entry['category__name']}, Средняя цена: {entry['average_price']}")
# Категория: Electronics, Средняя цена: 1250.00
# Категория: Furniture, Средняя цена: 450.00

Пример 3: ExpressionWrapper для разницы дат

Разница между двумя DateField требует явного output_field:

from django.db.models import Avg, F, ExpressionWrapper, fields
from store.models import ProductDetail

average_lifetime = ProductDetail.objects.annotate(
    lifetime=ExpressionWrapper(
        F('expiration_date') - F('manufacturing_date'),
        output_field=fields.DurationField()
    )
).aggregate(average_lifetime=Avg('lifetime'))['average_lifetime']

print(f"Средняя продолжительность жизни продуктов: {average_lifetime.days} дней")
# Средняя продолжительность жизни продуктов: 365 дней

Пример 4: Сортировка по аннотированному полю

annotate() создаёт виртуальное поле, по которому можно сортировать:

from django.db.models import Sum, F, Count
from store.models import Order

# Сортировка по вычисленной сумме заказа
orders_by_total = Order.objects.annotate(
    total=Sum(F('order_items__price') * F('order_items__quantity'))
).order_by('-total')

for order in orders_by_total:
    print(f"Заказ {order.id}, Общая стоимость: {order.total}")

# Сортировка по количеству позиций
orders_by_items = Order.objects.annotate(
    item_count=Count('order_items')
).order_by('-item_count')

for order in orders_by_items:
    print(f"Заказ {order.id}, Позиций: {order.item_count}")

Пример 5: Фильтр по временным меткам

from django.utils import timezone
from store.models import Order

one_month_ago = timezone.now() - timezone.timedelta(days=30)

recent_orders = Order.objects.filter(order_date__gte=one_month_ago)

print("Заказы за последний месяц:")
for order in recent_orders:
    print(f"Заказ {order.id}, Дата: {order.order_date}")

Пример 6: Срезы — LIMIT в QuerySet

from store.models import Product

# Первые 5 продуктов — SQL: SELECT ... LIMIT 5
first_five = Product.objects.all()[:5]
for product in first_five:
    print(f"{product.name}: {product.price}")

# Топ-10 дорогих — SQL: SELECT ... ORDER BY price DESC LIMIT 10
top_expensive = Product.objects.order_by('-price')[:10]
for product in top_expensive:
    print(f"{product.name}: {product.price}")

Пример 7: Сложная агрегация — заказы по клиентам

Группировка по нескольким полям клиента + Count + Sum одновременно:

from django.db.models import Count, Sum, F
from store.models import Order

orders_summary = Order.objects.values(
    'customer__first_name',
    'customer__last_name'
).annotate(
    order_count=Count('id'),
    total_spent=Sum(F('order_items__price') * F('order_items__quantity'))
).order_by('customer__last_name')

for entry in orders_summary:
    print(
        f"Клиент: {entry['customer__first_name']} {entry['customer__last_name']}, "
        f"Заказов: {entry['order_count']}, "
        f"Общая сумма: {entry['total_spent']}"
    )
← К оглавлению урока    Задания →