Агрегационные функции
from django.db.models import Count, Sum, Avg, Min, Max
| Функция | Синтаксис | Назначение |
Count | Count('id') / Count('id', distinct=True) | Количество записей |
Sum | Sum('price') | Сумма значений поля |
Avg | Avg('price') | Среднее значение |
Min | Min('price') | Минимальное значение |
Max | Max('price') | Максимальное значение |
Метод aggregate()
# Возвращает словарь
result = Model.objects.aggregate(
alias1=Func1('field1'),
alias2=Func2('field2'),
)
# result = {'alias1': значение, 'alias2': значение}
# Пример
stats = Book.objects.aggregate(
total=Count('id'),
avg_price=Avg('price'),
min_price=Min('price'),
max_price=Max('price'),
total_revenue=Sum('price'),
)
Метод annotate()
# Добавляет вычисленное поле к каждому объекту QuerySet
# Обычно используется с values() для группировки
# Количество книг по авторам
Book.objects.values('author').annotate(book_count=Count('id'))
# Аннотация без группировки (к каждому объекту)
Book.objects.annotate(discounted=F('price') * 0.9)
# Комбинация: год публикации + количество
from django.db.models.functions import ExtractYear
Book.objects.annotate(
year=ExtractYear('published_date')
).values('year').annotate(count=Count('id'))
Метод order_by()
# ASC (по возрастанию)
Model.objects.order_by('field')
# DESC (по убыванию) — минус перед именем поля
Model.objects.order_by('-field')
# По нескольким полям
Model.objects.order_by('field1', '-field2')
# По полю связанной модели (двойное подчёркивание)
Book.objects.order_by('publisher__name', 'title')
# Сортировка по аннотированному полю
Book.objects.annotate(cnt=Count('id')).order_by('-cnt')
Срезы QuerySet
# QuerySet[start:stop] → SQL: LIMIT (stop-start) OFFSET start
QuerySet[:5] # первые 5 → LIMIT 5
QuerySet[5:10] # с 6 по 10 → LIMIT 5 OFFSET 5
QuerySet[0:1] # только 1 → LIMIT 1 (аналог first())
# Комбинация с order_by
Book.objects.order_by('price')[:10] # 10 самых дешёвых
Book.objects.order_by('-published_date')[:5] # 5 самых новых
Подзапросы: Subquery и OuterRef
from django.db.models import OuterRef, Subquery, Min, Avg, Count
# Шаблон коррелированного подзапроса:
inner_qs = InnerModel.objects.filter(
fk_field=OuterRef('fk_field') # ссылка на поле внешнего запроса
).values('fk_field').annotate(
computed=AggrFunc('field')
).values('computed') # возвращает одно значение
outer_qs = OuterModel.objects.annotate(
alias=Subquery(inner_qs)
)
# Фильтрация через Subquery
OuterModel.objects.filter(field__lt=Subquery(inner_qs))
ExpressionWrapper
from django.db.models import F, ExpressionWrapper, fields
# Синтаксис
ExpressionWrapper(
expression, # арифметическое выражение
output_field=fields.ТипПоля() # обязательно!
)
# Доступные типы output_field
fields.FloatField()
fields.DecimalField(max_digits=10, decimal_places=2)
fields.IntegerField()
fields.DurationField()
# Пример
Book.objects.annotate(
discount_pct=ExpressionWrapper(
(1 - F('discounted_price') / F('price')) * 100,
output_field=fields.FloatField()
)
)
Временные метки
from django.utils import timezone
# Текущее время (с учётом часового пояса)
now = timezone.now()
# Временной интервал
delta = timezone.timedelta(days=30)
delta = timezone.timedelta(weeks=2)
delta = timezone.timedelta(hours=24)
# Фильтрация по относительным датам
recent = Model.objects.filter(
created_at__gte=timezone.now() - timezone.timedelta(days=7)
)
DRF: установка и подключение
# 1. Установка
pip install djangorestframework
# Фиксация в requirements.txt
pip freeze > requirements.txt
# 2. Добавление в INSTALLED_APPS (settings.py)
INSTALLED_APPS = [
...
'rest_framework',
]
# 3. Опциональные настройки (settings.py)
REST_FRAMEWORK = {
'DEFAULT_RENDERER_CLASSES': [
'rest_framework.renderers.JSONRenderer',
'rest_framework.renderers.BrowsableAPIRenderer',
],
'DEFAULT_PARSER_CLASSES': [
'rest_framework.parsers.JSONParser',
],
}
DRF: минимальный сериализатор
# serializers.py
from rest_framework import serializers
from .models import Task
# ModelSerializer — автоматически создаёт поля из модели
class TaskSerializer(serializers.ModelSerializer):
class Meta:
model = Task
fields = ['id', 'title', 'description', 'status', 'deadline']
# или fields = '__all__' для всех полей
# Использование в shell
from myapp.serializers import TaskSerializer
from myapp.models import Task
task = Task.objects.first()
serializer = TaskSerializer(task)
print(serializer.data) # OrderedDict с JSON-совместимыми данными
DRF: минимальный @api_view
# views.py
from rest_framework.decorators import api_view
from rest_framework.response import Response
from rest_framework import status
from .models import Task
from .serializers import TaskSerializer
@api_view(['GET'])
def task_list(request):
tasks = Task.objects.all()
serializer = TaskSerializer(tasks, many=True)
return Response(serializer.data)
@api_view(['POST'])
def task_create(request):
serializer = TaskSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)