⚡ Ключевые команды и паттерны
# ORM — дата и время
Project.objects.filter(date_of_creation__month=timezone.now().month)
ProjectFile.objects.annotate(weekday=ExtractWeekDay('created_at')).filter(weekday=2)
# ORM — агрегация
Project.objects.all().count()
Project.objects.annotate(avg_tasks=Avg('tasks__id'))
User.objects.annotate(cnt=Count('tasks__id')).values_list('username', 'cnt')
# ORM — сортировка
Task.objects.order_by('priority', 'due_date')
User.objects.annotate(cnt=Count('tasks__id')).order_by('-cnt')
# Пагинация
paginator = Paginator(Task.objects.all(), 10)
page = paginator.get_page(1)
# DRF — сериализатор
class MySerializer(ModelSerializer):
class Meta:
model = MyModel
fields = ['id', 'name']
# DRF — view
@api_view(['GET'])
def my_view(request):
qs = MyModel.objects.all()
data = MySerializer(qs, many=True)
return JsonResponse(data.data, status=status.HTTP_200_OK, safe=False)
← К оглавлению урока
ORM — работа с датой
| Метод / lookup | Описание | Пример |
__month | Фильтр по месяцу | filter(date__month=6) |
__year | Фильтр по году | filter(date__year=2025) |
__day | Фильтр по дню | filter(date__day=15) |
timezone.now() | Текущая дата/время | filter(date__month=timezone.now().month) |
ExtractWeekDay | День недели (1=вс, 2=пн, ...) | annotate(wd=ExtractWeekDay('created_at')) |
ORM — агрегация и аннотации
| Метод | Описание | Возвращает |
.count() | Количество объектов | int |
.aggregate(x=Count(...)) | Итоговое значение по всему QS | dict: {'x': N} |
.annotate(x=Count(...)) | Значение для каждого объекта | QuerySet с доп. полем x |
Count('field') | Количество связанных объектов | число |
Avg('field') | Среднее значение | float или None |
.values_list('f1','f2') | Выборка конкретных полей | QuerySet кортежей |
ORM — сортировка и пагинация
# Сортировка по нескольким полям
Task.objects.order_by('priority', 'due_date')
# Обратный порядок
User.objects.annotate(cnt=Count('tasks__id')).order_by('-cnt')
# Пагинация
from django.core.paginator import Paginator
paginator = Paginator(queryset, per_page)
page_obj = paginator.get_page(page_number) # безопасно
# page_obj.has_next(), page_obj.has_previous(), paginator.num_pages
DRF — установка и настройка
pip install djangorestframework
# settings.py
INSTALLED_APPS = [
...
'rest_framework',
]
# requirements.txt
djangorestframework
DRF — сериализаторы
| Паттерн | Описание |
ModelSerializer | Базовый класс для сериализаторов на основе модели |
Meta.fields = [...] | Список полей для сериализации |
Meta.fields = '__all__' | Все поля модели |
Serializer(obj) | Один объект |
Serializer(qs, many=True) | QuerySet / список объектов |
Serializer(data=request.data) | Десериализация (POST/PUT) |
.is_valid(raise_exception=True) | Валидация входных данных |
.save() | Создание или обновление объекта |
.data | Сериализованные данные (dict или list) |
Вложенный сериализатор
class TaskInfoSerializer(serializers.ModelSerializer):
tags = TagsSerializer(many=True) # вложенный
class Meta:
model = Task
fields = ['id', 'name', 'tags', ...]
DRF — функциональные views
from rest_framework.request import Request
from rest_framework.decorators import api_view
from rest_framework import status
from django.http import JsonResponse
# GET — список
@api_view(['GET'])
def get_all_items(request: Request) -> JsonResponse:
qs = MyModel.objects.all()
if not qs.exists():
return JsonResponse([], status=status.HTTP_204_NO_CONTENT, safe=False)
data = MySerializer(qs, many=True)
return JsonResponse(data.data, status=status.HTTP_200_OK, safe=False)
# GET — один объект по id
@api_view(['GET'])
def get_item_by_id(request: Request, item_id: int) -> JsonResponse:
try:
obj = MyModel.objects.get(id=item_id)
except MyModel.DoesNotExist:
return JsonResponse({}, status=status.HTTP_204_NO_CONTENT)
data = MySerializer(obj)
return JsonResponse(data.data, status=status.HTTP_200_OK)
# POST — создание
@api_view(['POST'])
def create_item(request: Request) -> JsonResponse:
serializer = MySerializer(data=request.data)
if serializer.is_valid(raise_exception=True):
serializer.save()
return JsonResponse(serializer.data, status=status.HTTP_201_CREATED)
return JsonResponse(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
# PUT — обновление
@api_view(['PUT'])
def update_item(request: Request, item_id: int) -> JsonResponse:
try:
obj = MyModel.objects.get(id=item_id)
except MyModel.DoesNotExist:
return JsonResponse({}, status=status.HTTP_204_NO_CONTENT)
serializer = MySerializer(obj, request.data)
if serializer.is_valid(raise_exception=True):
serializer.save()
return JsonResponse(serializer.data, status=status.HTTP_200_OK)
# DELETE — удаление
@api_view(['DELETE'])
def delete_item(request: Request, item_id: int) -> JsonResponse:
try:
obj = MyModel.objects.get(id=item_id)
except MyModel.DoesNotExist:
return JsonResponse({}, status=status.HTTP_204_NO_CONTENT)
obj.delete()
return JsonResponse({'message': 'Deleted successfully'}, status=status.HTTP_200_OK)
DRF — регистрация URL
# management_app/urls.py
from django.urls import path
from management_app.views import (
get_all_projects, get_all_tasks, get_all_tags,
get_tag_by_id, create_new_tag, update_required_tag,
delete_required_tag, get_task_by_id
)
urlpatterns = [
path('projects/', get_all_projects),
path('tasks/', get_all_tasks),
path('tasks/<int:task_id>/', get_task_by_id),
path('tags/', get_all_tags),
path('tags/create/', create_new_tag), # ВАЖНО: до <int:tag_id>
path('tags/<int:tag_id>/', get_tag_by_id),
path('tags/<int:tag_id>/update/', update_required_tag),
path('tags/<int:tag_id>/delete/', delete_required_tag),
]
# project_management/urls.py
from django.urls import path, include
urlpatterns = [
path('management_app/', include('management_app.urls')),
]
Маршрут tags/create/ должен стоять перед tags/<int:tag_id>/, иначе Django попытается преобразовать строку "create" в int и выдаст 404.