📖 Теория: Представления и маршруты DRF
⚡ Ключевые концепции
- ModelViewSet — ViewSet с полным CRUD; регистрируется через Router
- DefaultRouter — автоматически создаёт все URL (list, detail, create, update, delete)
- ListCreateAPIView — GET (список) + POST (создание)
- RetrieveUpdateDestroyAPIView — GET (деталь) + PUT/PATCH + DELETE
- get_serializer_class() — возвращает разные сериализаторы по методу запроса
- DjangoFilterBackend — фильтрация через query-параметры (?category=1&price=100)
ModelViewSet и DefaultRouter
ModelViewSet — самый высокоуровневый инструмент DRF для создания CRUD API. Один класс заменяет 5 отдельных представлений (list, create, retrieve, update, destroy).
from rest_framework import viewsets
from .models import Category
from .serializers import CategorySerializer
class CategoryViewSet(viewsets.ModelViewSet):
queryset = Category.objects.all()
serializer_class = CategorySerializer
DefaultRouter автоматически генерирует маршруты:
from rest_framework.routers import DefaultRouter
from .views import CategoryViewSet
router = DefaultRouter()
router.register(r'categories', CategoryViewSet)
urlpatterns = [
path('', include(router.urls)),
]
Что создаёт DefaultRouter:
GET /categories/— список всех категорийPOST /categories/— создание категорииGET /categories/{id}/— получение категории по IDPUT /categories/{id}/— полное обновлениеPATCH /categories/{id}/— частичное обновлениеDELETE /categories/{id}/— удаление
Когда использовать ViewSet, а когда Generic Views
В этом практикуме используются оба подхода — в зависимости от требований модели:
| Подход | Когда подходит | Модели в практикуме |
|---|---|---|
ModelViewSet |
Один сериализатор на все операции | Category, Supplier, Address |
Generic Views |
Разные сериализаторы для GET и POST/PUT | Product, ProductDetail, Customer, Order, OrderItem |
Generic Views: ListCreateAPIView и RetrieveUpdateDestroyAPIView
Когда для GET и POST/PUT нужны разные сериализаторы (например, при чтении возвращаем вложенные объекты, при записи принимаем FK-ключи), используем Generic Views с переопределением get_serializer_class():
from rest_framework.generics import ListCreateAPIView
from .models import Product
from .serializers import ProductSerializer, ProductCreateUpdateSerializer
class ProductListCreateView(ListCreateAPIView):
queryset = Product.objects.all()
def get_serializer_class(self):
if self.request.method == 'GET':
return ProductSerializer # возвращает вложенные объекты
return ProductCreateUpdateSerializer # принимает FK-ключи
Для детального представления:
from rest_framework.generics import RetrieveUpdateDestroyAPIView
class ProductDetailUpdateDeleteView(RetrieveUpdateDestroyAPIView):
queryset = Product.objects.all()
def get_serializer_class(self):
if self.request.method == 'GET':
return ProductSerializer
return ProductCreateUpdateSerializer
URL для Generic Views регистрируются вручную:
from django.urls import path
from .views import ProductListCreateView, ProductDetailUpdateDeleteView
urlpatterns = [
path('products/', ProductListCreateView.as_view()),
path('products/<int:pk>/', ProductDetailUpdateDeleteView.as_view()),
]
DjangoFilterBackend и фильтрация
Для добавления фильтрации через query-параметры используется пакет django-filter:
# settings.py
INSTALLED_APPS = [
# ...
'django_filters',
]
# views.py
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']
После настройки можно делать запросы: GET /api/products/?category=2&price=100
Установка django-filter:
pip install django-filter. Затем обязательно добавить 'django_filters' в INSTALLED_APPS. Без этого шага DRF не увидит бекенд фильтрации.