⚖️ Старый vs Новый: Эволюция представлений DRF

⚡ Ключевые изменения

  • APIView (ручной CRUD) → ModelViewSet (автоматический)
  • Ручные URL для каждого метода → DefaultRouter генерирует автоматически
  • Отдельные view-классы для list/detail → ListCreateAPIView + RetrieveUpdateDestroyAPIView
  • Ручная фильтрация через queryset → DjangoFilterBackend + filterset_fields

1. Ручные CRUD-представления → ModelViewSet

Старый подход (из лекции)

# Много кода: отдельный класс для каждого действия
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status

class CategoryListView(APIView):
    def get(self, request):
        categories = Category.objects.all()
        serializer = CategorySerializer(categories, many=True)
        return Response(serializer.data)

    def post(self, request):
        serializer = CategorySerializer(data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data, status=201)
        return Response(serializer.errors, status=400)

class CategoryDetailView(APIView):
    def get_object(self, pk):
        try:
            return Category.objects.get(pk=pk)
        except Category.DoesNotExist:
            raise Http404

    def get(self, request, pk):
        category = self.get_object(pk)
        serializer = CategorySerializer(category)
        return Response(serializer.data)

    def put(self, request, pk):
        category = self.get_object(pk)
        serializer = CategorySerializer(category, data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data)
        return Response(serializer.errors, status=400)

    def delete(self, request, pk):
        category = self.get_object(pk)
        category.delete()
        return Response(status=204)

Современный подход (DRF 3.x)

# Минимальный код: всё в одном классе
from rest_framework import viewsets
from .models import Category
from .serializers import CategorySerializer

class CategoryViewSet(viewsets.ModelViewSet):
    queryset = Category.objects.all()
    serializer_class = CategorySerializer

# 3 строки кода вместо 40+
# DRF автоматически реализует:
# - list (GET /categories/)
# - create (POST /categories/)
# - retrieve (GET /categories/{pk}/)
# - update (PUT /categories/{pk}/)
# - partial_update (PATCH /categories/{pk}/)
# - destroy (DELETE /categories/{pk}/)

2. Ручные URL → DefaultRouter

Старый подход

# urls.py — каждый URL прописывается вручную
from django.urls import path
from .views import CategoryListView, CategoryDetailView

urlpatterns = [
    path('categories/', CategoryListView.as_view()),
    path('categories/<int:pk>/', CategoryDetailView.as_view()),
    # Плюс PATCH нужно добавлять отдельно...
]

Современный подход

# urls.py — Router генерирует все URL
from rest_framework.routers import DefaultRouter
from .views import CategoryViewSet

router = DefaultRouter()
router.register(r'categories', CategoryViewSet)

urlpatterns = [
    path('', include(router.urls)),
]
# Все 6 URL созданы автоматически

3. Ручная фильтрация → DjangoFilterBackend

Старый подход

# Ручная фильтрация в get_queryset()
class ProductListView(ListAPIView):
    serializer_class = ProductSerializer

    def get_queryset(self):
        queryset = Product.objects.all()
        category = self.request.query_params.get('category')
        price = self.request.query_params.get('price')
        if category:
            queryset = queryset.filter(category=category)
        if price:
            queryset = queryset.filter(price=price)
        return queryset
# Много boilerplate, нет документации в Browsable API

Современный подход

# DjangoFilterBackend — декларативно
from django_filters.rest_framework import DjangoFilterBackend

class ProductViewSet(viewsets.ModelViewSet):
    queryset = Product.objects.all()
    serializer_class = ProductSerializer
    filter_backends = [DjangoFilterBackend]
    filterset_fields = ['category', 'price']
# Автоматически:
# - валидация query-параметров
# - документация в Browsable API
# - фильтрация работает через ?field=value
Итог: Лекция показывает оба подхода для понимания основ. В реальных проектах на Django 5.x + DRF 3.15+ используются ModelViewSet, DefaultRouter и DjangoFilterBackend. Ручные APIView остаются нужными только для нестандартных эндпоинтов, которые не вписываются в CRUD-паттерн.
← К оглавлению урока    Задания →