DjangoMiddleSystem design

Как реализовать версионирование в Django REST API?

Django REST Framework поддерживает версионирование через URLPath, Namespace, QueryParameter и Accept-заголовок. Версия извлекается из request.version и используется для маршрутизации логики.

Версионирование в Django REST Framework

DRF предоставляет четыре встроенных класса версионирования, настраиваемых глобально через DEFAULT_VERSIONING_CLASS или на уровне конкретного view через атрибут versioning_class.

Способы версионирования

  • URLPathVersioning — версия в пути: /api/v1/users/
  • NamespaceVersioning — версия через namespace Django URL
  • QueryParameterVersioning/api/users/?version=v1
  • AcceptHeaderVersioningAccept: application/json; version=v1

Настройка URLPathVersioning

# settings.py
REST_FRAMEWORK = {
    "DEFAULT_VERSIONING_CLASS": "rest_framework.versioning.URLPathVersioning",
    "DEFAULT_VERSION": "v1",
    "ALLOWED_VERSIONS": ["v1", "v2"],
    "VERSION_PARAM": "version",
}
# urls.py
from django.urls import path, include

urlpatterns = [
    path("api/<version>/", include("myapp.urls")),
]
# views.py
from rest_framework.views import APIView
from rest_framework.response import Response

class UserView(APIView):
    def get(self, request, *args, **kwargs):
        if request.version == "v2":
            data = {"id": 1, "full_name": "Alice Smith", "email": "alice@example.com"}
        else:
            data = {"id": 1, "name": "Alice"}
        return Response(data)

Версионирование на уровне ViewSet с разными сериализаторами

# serializers.py
from rest_framework import serializers
from .models import User

class UserSerializerV1(serializers.ModelSerializer):
    class Meta:
        model = User
        fields = ["id", "username"]

class UserSerializerV2(serializers.ModelSerializer):
    class Meta:
        model = User
        fields = ["id", "username", "email", "date_joined"]

# views.py
from rest_framework import viewsets
from .serializers import UserSerializerV1, UserSerializerV2
from .models import User

class UserViewSet(viewsets.ReadOnlyModelViewSet):
    queryset = User.objects.all()

    def get_serializer_class(self):
        if self.request.version == "v2":
            return UserSerializerV2
        return UserSerializerV1

Роутер с версионированием

# urls.py
from rest_framework.routers import DefaultRouter
from .views import UserViewSet

router = DefaultRouter()
router.register(r"users", UserViewSet, basename="user")

urlpatterns = [
    path("api/<version>/", include(router.urls)),
]

Подводные камни

  • Забытый ALLOWED_VERSIONS — если не задать список, DRF принимает любую строку как валидную версию, и опечатка v11 не вызовет 404.
  • Дублирование бизнес-логики — ветвление if request.version разбросано по всему коду вместо инкапсуляции в отдельные view-классы или сериализаторы.
  • Устаревшие версии не удаляются — v1 живёт вечно; отсутствует политика deprecation с заголовком Sunset и сроком отключения.
  • AcceptHeaderVersioning ломает кэширование — CDN и прокси кэшируют ответы без учёта заголовка Accept, клиент получает данные чужой версии.
  • Несогласованность URL-схемы — часть эндпоинтов версионирована, часть нет; документация (drf-spectacular) генерирует смешанную схему.
  • Тесты не покрывают все версии — тест для v2 написан, для v1 забыт; регрессия обнаруживается в проде.
  • DEFAULT_VERSION не соответствует реальному поведению — если клиент не передаёт версию, он получает v1, хотя бизнес-логика уже перешла на v2.

Common mistakes

  • Описывать api versioning только как термин и не показывать механизм на минимальном примере.
  • Игнорировать ошибки, пустые данные, конкурентный доступ или границы транзакции.
  • Не связывать поведение с официальным контрактом Django и реальной эксплуатацией.

What the interviewer is testing

  • Объясняет api versioning через последовательность действий, а не через набор ключевых слов.
  • Приводит короткий кодовый пример или production-сценарий с ожидаемым поведением.
  • Называет хотя бы один риск: производительность, безопасность, транзакции, память или сопровождение.

Sources

Related topics