✅ Разбор ответов на самопроверку
⚡ Ключевые ответы
- get_queryset() позволяет фильтровать динамически;
queryset— статичный набор. - ModelViewSet — когда нужен полный CRUD; Generic Views — когда нужно ограничить операции.
- DefaultRouter добавляет корневую страницу API; SimpleRouter — нет.
- SoftDeleteManager автоматически исключает помеченные записи из всех запросов.
- CursorPagination — для часто изменяемых данных; PageNumberPagination — для стабильных.
Блок A: GenericAPIView и Generic Views
Ответ 1: GenericAPIView
GenericAPIView расширяет APIView, добавляя встроенную поддержку queryset и serializer_class, а также методы для работы с данными (get_queryset, get_object, get_serializer). Он является основой для Generic Views и ViewSets, но сам по себе не реализует никаких HTTP-методов.
APIView — базовый класс с методами get/post/put/patch/delete, которые нужно реализовывать вручную. GenericAPIView добавляет шаблонные инструменты для работы с моделями.
Ответ 2: queryset и serializer_class
queryset — определяет набор данных, с которым работает представление. serializer_class — указывает класс сериализатора для преобразования данных. Оба атрибута можно переопределить через методы get_queryset() и get_serializer_class() для динамического поведения.
Ответ 3: Динамический queryset
Метод get_queryset(). Он вызывается при каждом запросе, поэтому в нём можно использовать параметры запроса (self.request.query_params), данные пользователя (self.request.user) и другие динамические данные.
def get_queryset(self):
queryset = Book.objects.all()
author = self.request.query_params.get('author')
if author:
queryset = queryset.filter(author=author)
return queryset
Ответ 4: Все 9 Generic Views
| Класс | Методы | Назначение |
|---|---|---|
| ListAPIView | GET | Список объектов |
| CreateAPIView | POST | Создание |
| RetrieveAPIView | GET | Один объект |
| UpdateAPIView | PUT/PATCH | Обновление |
| DestroyAPIView | DELETE | Удаление |
| ListCreateAPIView | GET + POST | Список + создание |
| RetrieveUpdateAPIView | GET + PUT/PATCH | Чтение + обновление |
| RetrieveDestroyAPIView | GET + DELETE | Чтение + удаление |
| RetrieveUpdateDestroyAPIView | GET + PUT/PATCH + DELETE | Полный CRUD для одного объекта |
Ответ 5: lookup_field и lookup_url_kwarg
lookup_field указывает поле модели для поиска объекта (по умолчанию 'pk'). lookup_url_kwarg указывает имя параметра URL, из которого берётся значение.
class GenreDetailView(RetrieveUpdateDestroyAPIView):
queryset = Genre.objects.all()
serializer_class = GenreSerializer
lookup_field = 'name' # ищем по полю name
lookup_url_kwarg = 'genre_name' # из URL <str:genre_name>
# GET /genres/comedy/ → ищет Genre.objects.get(name='comedy')
Ответ 6: get_object()
Используется для получения одного экземпляра модели. Применяет lookup_field и lookup_url_kwarg, автоматически вызывает check_object_permissions() и бросает Http404 при отсутствии. Можно переопределить для добавления дополнительных условий фильтрации (например, исключения заблокированных записей).
Ответ 7: get_serializer_context()
Переопределить метод get_serializer_context() и добавить нужные данные в словарь контекста. Сериализатор получает контекст через self.context.
def get_serializer_context(self):
context = super().get_serializer_context()
context['include_related'] = True
return context
# В сериализаторе:
def to_representation(self, instance):
rep = super().to_representation(instance)
if self.context.get('include_related'):
rep['extra'] = ...
return rep
Блок B: ViewSets и Router
Ответ 8: ViewSets
ViewSet — класс, объединяющий логику нескольких HTTP-методов (list, create, retrieve, update, destroy) в одном классе. Главное преимущество — автоматическая маршрутизация через Router и меньше дублирования кода. Вместо 2 отдельных Generic Views достаточно одного ViewSet.
Ответ 9: Три вида ViewSets
- ModelViewSet — полный CRUD; когда нужны все операции.
- ReadOnlyModelViewSet — только list и retrieve; для read-only API.
- GenericViewSet — базовый класс, набор операций задаётся вручную через миксины; для кастомных комбинаций.
Ответ 10: Кастомная логика перед сохранением
Переопределить метод perform_create(self, serializer) или create(self, request, *args, **kwargs). Первый вызывается внутри стандартного create и подходит для добавления данных при сохранении (serializer.save(owner=request.user)). Второй даёт полный контроль над ответом.
Ответ 11: @action
Декоратор @action добавляет кастомный метод к ViewSet. Параметры:
detail=True→ URL:/items/{pk}/action/detail=False→ URL:/items/action/methods=['get', 'post']— список допустимых HTTP-методовurl_path='custom-name'— переопределяет суффикс URL
Ответ 12: DefaultRouter vs SimpleRouter
DefaultRouter добавляет корневую страницу /api/, которая показывает список всех зарегистрированных маршрутов в формате JSON. SimpleRouter генерирует те же маршруты для CRUD, но без корневой страницы. DefaultRouter удобнее при разработке.
Блок C: Фильтрация, пагинация, логирование
Ответ 13: filter_backends
Атрибут filter_backends определяет, какие механизмы фильтрации применяются к queryset. Три стандартных:
DjangoFilterBackend— фильтрация по точным полям (filterset_fields)SearchFilter— текстовый поиск (search_fields)OrderingFilter— сортировка (ordering_fields)
Ответ 14: Параметры запроса filter backends
- DjangoFilterBackend:
?author=Fitzgerald(по имени поля) - SearchFilter:
?search=Gatsby - OrderingFilter:
?ordering=price(ASC),?ordering=-price(DESC)
Ответ 15: Три класса пагинации
- PageNumberPagination — навигация по номеру страницы:
?page=2. Прост, но при вставках данных страницы могут смещаться. - LimitOffsetPagination — задаётся
?limit=5&offset=10. Гибко, привычно для SQL-разработчиков. - CursorPagination — использует непрозрачный курсор. Стабильна при частых изменениях данных, но нельзя перейти на произвольную страницу.
Ответ 16: Глобальная пагинация
# settings.py
REST_FRAMEWORK = {
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
'PAGE_SIZE': 10,
}
# Применяется ко всем представлениям, кроме тех, где явно указан pagination_class
Ответ 17: Логирование SQL
# settings.py
LOGGING = {
'version': 1,
'handlers': {
'console': {'level': 'DEBUG', 'class': 'logging.StreamHandler'},
},
'loggers': {
'django.db.backends': {
'handlers': ['console'],
'level': 'DEBUG',
},
},
}
# Требует DEBUG = True
Блок D: Soft Deletion, ленивая загрузка, транзакции
Ответ 18: Soft Deletion
Мягкое удаление — записи не удаляются физически, а помечаются флагом is_deleted=True. Шаги реализации:
- Добавить поля
is_deletedиdeleted_atв модель. - Переопределить метод
delete()модели — вместо физического удаления установить флаги. - Создать
SoftDeleteManagerс фильтромis_deleted=False.
Ответ 19: Менеджер модели
Менеджер модели — класс, управляющий запросами (Model.objects). SoftDeleteManager нужен, чтобы все запросы (.all(), .filter(), .get()) автоматически исключали записи с is_deleted=True, без необходимости добавлять этот фильтр вручную везде.
Ответ 20: Ленивая загрузка и N+1
Ленивая загрузка — QuerySet не выполняет SQL до момента обращения к данным. Это позволяет цеплять .filter(), .order_by() и т.д. без лишних запросов.
Проблема N+1: при итерации по объектам с доступом к связанным данным каждый объект вызывает отдельный запрос.
Решения: select_related() для FK/OneToOne; prefetch_related() для ManyToMany и обратных FK.
Ответ 21: select_related vs prefetch_related
select_related()— выполняет SQL JOIN, загружает связанные объекты в одном запросе. Применяется для ForeignKey и OneToOneField.prefetch_related()— выполняет отдельный запрос для связанных объектов и объединяет в Python. Применяется для ManyToManyField и обратных ForeignKey (related_name).
Ответ 22: Транзакции и API
Транзакция — группа операций, выполняемых как единое целое (атомарность, изолированность, консистентность, долговечность — ACID).
transaction.atomic— создаёт атомарный блок (декоратор или контекстный менеджер)transaction.on_commit— действие после успешного коммитаtransaction.set_rollback— явный откат транзакции в конце блока
Ответ 23: @transaction.atomic vs with transaction.atomic()
Оба обеспечивают атомарность, но:
@transaction.atomic— декоратор на всю функцию. Если функция успешно завершается, транзакция фиксируется; при исключении — откатывается.with transaction.atomic():— контекстный менеджер для части кода внутри функции. Можно вложить несколько блоков; вложенные создают точки сохранения (savepoints).