📖 Теория: ORM-запросы, сериализаторы и базовые views
Контекст практикума — всё необходимое перед задачами
⚡ Самое важное
- annotate() + ExtractWeekDay: добавляет вычисляемое поле к каждой строке QuerySet
- aggregate() + Count/Avg: возвращает один словарь с итоговым значением
- Paginator(qs, N): разбивает QuerySet на страницы по N элементов
- ModelSerializer: автоматически генерирует поля из модели, Meta.fields задаёт список
- @api_view(['GET']): декоратор DRF превращает функцию во view с поддержкой DRF-запроса
- JsonResponse(data, safe=False): нужен
safe=Falseесли data — список, а не словарь
Часть 1: Продвинутые ORM-запросы
Фильтрация по дате — __month, __year
Django ORM позволяет фильтровать по отдельным компонентам даты через lookup-суффиксы.
# Проекты, созданные в текущем месяце
from django.utils import timezone
Project.objects.filter(date_of_creation__month=timezone.now().month)
# Файлы, созданные в конкретный год
ProjectFile.objects.filter(created_at__year=2025)
datetime.now(), так как учитывает настройки часового пояса Django.
ExtractWeekDay — день недели из даты
ExtractWeekDay — функция для аннотации QuerySet. Извлекает номер дня недели из поля типа DateField/DateTimeField.
from django.db.models.functions import ExtractWeekDay
files = ProjectFile.objects.annotate(
weekday=ExtractWeekDay('created_at')
).filter(weekday=2) # 2 = понедельник
annotate() — агрегация по строкам
annotate() добавляет вычисляемое поле к каждому объекту QuerySet.
from django.db.models import Count, Avg
# Количество файлов для каждого проекта (добавляет поле file_count к каждому проекту)
Project.objects.annotate(file_count=Count('project_files'))
# Среднее количество задач на каждом проекте
Project.objects.annotate(avg_tasks=Avg('tasks__id'))
aggregate() — одно итоговое значение
aggregate() возвращает словарь с одним итоговым значением по всему QuerySet.
from django.db.models import Count
# Общее количество проектов
Project.objects.all().count() # метод count()
Project.objects.aggregate(n=Count('id')) # aggregate — тоже работает
values_list() — только нужные поля
# Получить только username и count_of_tasks
User.objects.annotate(
count_of_tasks=Count('tasks__id')
).values_list('username', 'count_of_tasks')
order_by() — сортировка по нескольким полям
# Сортировка задач по приоритету, затем по дате выполнения
Task.objects.order_by('priority', 'due_date')
# Обратный порядок: '-' перед именем поля
User.objects.annotate(
count_of_tasks=Count('tasks__id')
).order_by('-count_of_tasks')
Paginator — пагинация
Paginator из django.core.paginator разбивает QuerySet на страницы фиксированного размера.
from django.core.paginator import Paginator
tasks = Task.objects.all()
paginator = Paginator(tasks, 10) # 10 объектов на страницу
page = paginator.get_page(1) # первая страница
for task in page:
print(task.name)
get_page(n) безопаснее page(n): не бросает исключение если номер страницы выходит за границы.
Часть 2: Django REST Framework (DRF)
Установка и подключение
# Установка
pip install djangorestframework
# requirements.txt
djangorestframework
# settings.py
INSTALLED_APPS = [
...
'rest_framework',
]
ModelSerializer
ModelSerializer — сериализатор, который автоматически создаёт поля на основе модели Django. Минимально нужно указать model и fields в классе Meta.
from rest_framework.serializers import ModelSerializer
from management_app.models import Project
class AllProjectsSerializer(ModelSerializer):
class Meta:
model = Project
fields = ['id', 'name'] # конкретные поля
# fields = '__all__' # все поля модели
Для сериализации QuerySet передать many=True:
serializer = AllProjectsSerializer(Project.objects.all(), many=True)
data = serializer.data # список словарей
Вложенные сериализаторы
Поле модели можно представить не как ID, а как вложенный объект, используя другой сериализатор как тип поля:
class TaskInfoSerializer(serializers.ModelSerializer):
tags = TagsSerializer(many=True) # вложенный сериализатор
class Meta:
model = Task
fields = ['id', 'name', 'status', 'priority', 'tags', ...]
@api_view — функциональные views
Декоратор @api_view оборачивает обычную функцию в DRF-обработчик. В списке передаются разрешённые HTTP-методы.
from rest_framework.request import Request
from rest_framework.decorators import api_view
from rest_framework import status
from django.http import JsonResponse
@api_view(['GET'])
def get_all_projects(request: Request) -> JsonResponse:
projects = Project.objects.all()
if not projects.exists():
return JsonResponse([], status=status.HTTP_204_NO_CONTENT, safe=False)
data = AllProjectsSerializer(projects, many=True)
return JsonResponse(data.data, status=status.HTTP_200_OK, safe=False)
Структура URL-маршрутов
# management_app/urls.py
from django.urls import path
from management_app.views import get_all_projects
urlpatterns = [
path('projects/', get_all_projects),
]
# project_management/urls.py (главный urls.py проекта)
from django.urls import path, include
urlpatterns = [
path('management_app/', include('management_app.urls')),
]
# Итоговый URL: /management_app/projects/
HTTP-статусы в DRF
| Константа | Код | Когда использовать |
|---|---|---|
status.HTTP_200_OK | 200 | Успешный GET / PUT |
status.HTTP_201_CREATED | 201 | Успешный POST (создание) |
status.HTTP_204_NO_CONTENT | 204 | Нет данных / успешное DELETE |
status.HTTP_400_BAD_REQUEST | 400 | Ошибка валидации |
status.HTTP_404_NOT_FOUND | 404 | Объект не найден |