Урок по треку Python для веба: Django и FastAPI 8 мин

Django REST Framework: сериализаторы, вьюсеты, права и пагинация

Сериализаторы, ViewSet и роутеры, права, пагинация, фильтры и троттлинг.

Большинство Django-проектов в России отдают API через Django REST Framework (DRF). На собесе спрашивают, как устроены сериализаторы, чем APIView отличается от ViewSet, как работают права и где в DRF прячется N+1.

Сериализатор

Сериализатор делает две вещи: превращает объекты в JSON-совместимые данные и валидирует входящие данные.

class OrderSerializer(serializers.ModelSerializer):
    customer_name = serializers.CharField(source='customer.name', read_only=True)

    class Meta:
        model = Order
        fields = ['id', 'status', 'total', 'customer_name', 'created_at']
        read_only_fields = ['status', 'created_at']

    def validate_total(self, value):
        if value <= 0:
            raise serializers.ValidationError('Сумма должна быть больше нуля')
        return value

Валидация идёт по слоям: поля (типы, required, max_length), методы validate_<field>, общий validate(self, attrs) для проверок между полями, валидаторы модели вроде уникальности. После is_valid() в serializer.validated_data лежат чистые данные, а serializer.save() вызывает create или update.

Важно явно перечислять fields. fields = '__all__' завтра отдаст наружу новое поле password_hash или internal_note.

Вьюхи

  • APIView: методы get, post и т.д., всё вручную.
  • Generic-вьюхи (ListCreateAPIView, RetrieveUpdateDestroyAPIView): типовые операции с queryset и serializer_class.
  • ViewSet и ModelViewSet: набор действий list, retrieve, create, update, partial_update, destroy в одном классе, URL создаёт роутер.
class OrderViewSet(viewsets.ModelViewSet):
    serializer_class = OrderSerializer
    permission_classes = [IsAuthenticated]

    def get_queryset(self):
        return (Order.objects.filter(customer__user=self.request.user)
                .select_related('customer'))

    @action(detail=True, methods=['post'])
    def cancel(self, request, pk=None):
        order = self.get_object()
        ...

get_queryset с фильтром по пользователю это и безопасность, и производительность: чужие объекты не видны даже по прямому id, а select_related убирает N+1.

Аутентификация и права

  • Authentication classes определяют, кто пришёл: сессия, токен, JWT (через simplejwt).
  • Permission classes решают, можно ли: IsAuthenticated, IsAdminUser, DjangoModelPermissions, свои.
  • has_permission(request, view) проверяется для всего запроса, has_object_permission(request, view, obj) для конкретного объекта, но только когда вызван get_object(). Для списков объектная проверка не вызывается, там фильтруют get_queryset.

Пагинация, фильтры, троттлинг

  • PageNumberPagination, LimitOffsetPagination и CursorPagination. Курсорная стабильна при вставках и не тормозит на глубоких страницах, но не умеет прыгать на страницу N.
  • Фильтры: django-filter, SearchFilter, OrderingFilter. Разрешённые поля сортировки задают явно.
  • Троттлинг: AnonRateThrottle, UserRateThrottle, ScopedRateThrottle; счётчики хранятся в кеше, поэтому нужен общий кеш (Redis) на все процессы.

Где в DRF N+1

Вложенные сериализаторы и поля с source='customer.name' обращаются к связям для каждого объекта списка. Решение в get_queryset: select_related и prefetch_related под те поля, что отдаёт сериализатор. SerializerMethodField, который делает запрос внутри, тоже источник N+1.

Частые ошибки

  • fields = '__all__' и утечка служебных полей.
  • Проверка прав только в has_object_permission при незащищённом списке.
  • queryset = Order.objects.all() без фильтра по пользователю: IDOR.
  • Вложенные сериализаторы без prefetch_related.
  • Запись во вложенные сериализаторы без переопределения create и update (DRF по умолчанию это не поддерживает).

Что спросят на собесе

  • Что делает сериализатор, как устроена валидация.
  • Чем APIView, generic-вьюхи и ViewSet отличаются.
  • Как работают permission classes, в чём разница has_permission и has_object_permission.
  • Какие бывают пагинации, чем хороша курсорная.
  • Как найти и убрать N+1 в DRF.

Закрепите за 5 минут

После урока в тренажёре 3-5 проверочных вопросов, дальше модуль уходит в повторения.