Поля сериализатора для связей
| Поле | Синтаксис | Запись | Возвращает |
StringRelatedField |
serializers.StringRelatedField() |
Нет |
str(obj) |
SlugRelatedField |
serializers.SlugRelatedField(slug_field='поле', queryset=...) |
По slug |
Значение slug-поля |
PrimaryKeyRelatedField |
serializers.PrimaryKeyRelatedField(queryset=...) |
По ID |
Integer (PK) |
| M2M через PK |
serializers.PrimaryKeyRelatedField(queryset=..., many=True) |
Список ID |
Список Integer |
StringRelatedField
from rest_framework import serializers
class BookSerializer(serializers.ModelSerializer):
# Отображает Publisher.__str__() — только чтение
publisher = serializers.StringRelatedField()
class Meta:
model = Book
fields = '__all__'
SlugRelatedField
class BookSerializer(serializers.ModelSerializer):
publisher = serializers.SlugRelatedField(
slug_field='slug', # поле модели Publisher
queryset=Publisher.objects.all() # обязателен для записи
)
class Meta:
model = Book
fields = '__all__'
# Для read-only (без записи) — queryset не нужен:
publisher = serializers.SlugRelatedField(
slug_field='slug',
read_only=True
)
PrimaryKeyRelatedField
class BookSerializer(serializers.ModelSerializer):
# ForeignKey по ID
publisher = serializers.PrimaryKeyRelatedField(
queryset=Publisher.objects.all()
)
# ManyToManyField по списку ID
genres = serializers.PrimaryKeyRelatedField(
queryset=Genre.objects.all(),
many=True
)
class Meta:
model = Book
fields = '__all__'
APIView
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
class ItemListCreateView(APIView):
def get(self, request):
"""GET — список объектов"""
items = Item.objects.all()
serializer = ItemSerializer(items, many=True)
return Response(serializer.data)
def post(self, request):
"""POST — создание объекта"""
serializer = ItemSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
class ItemDetailView(APIView):
def get_object(self, pk):
"""Вспомогательный метод — избегает дублирования try/except"""
try:
return Item.objects.get(pk=pk)
except Item.DoesNotExist:
return None
def get(self, request, pk):
item = self.get_object(pk)
if item is None:
return Response({'error': 'Not found'}, status=status.HTTP_404_NOT_FOUND)
return Response(ItemSerializer(item).data)
def put(self, request, pk):
item = self.get_object(pk)
if item is None:
return Response({'error': 'Not found'}, status=status.HTTP_404_NOT_FOUND)
serializer = ItemSerializer(item, data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
def patch(self, request, pk):
item = self.get_object(pk)
if item is None:
return Response({'error': 'Not found'}, status=status.HTTP_404_NOT_FOUND)
# partial=True — разрешает частичное обновление
serializer = ItemSerializer(item, data=request.data, partial=True)
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
def delete(self, request, pk):
item = self.get_object(pk)
if item is None:
return Response({'error': 'Not found'}, status=status.HTTP_404_NOT_FOUND)
item.delete()
return Response(status=status.HTTP_204_NO_CONTENT)
Регистрация APIView в urls.py
from django.urls import path
from .views import ItemListCreateView, ItemDetailView
urlpatterns = [
path('items/', ItemListCreateView.as_view(), name='item-list'),
path('items/<int:pk>/', ItemDetailView.as_view(), name='item-detail'),
]
Generic Views — шаблоны
from rest_framework import generics
# Только список
class BookListView(generics.ListAPIView):
queryset = Book.objects.all()
serializer_class = BookSerializer
# Список + создание
class BookListCreateView(generics.ListCreateAPIView):
queryset = Book.objects.all()
serializer_class = BookSerializer
# Получение + обновление + удаление
class BookDetailView(generics.RetrieveUpdateDestroyAPIView):
queryset = Book.objects.all()
serializer_class = BookSerializer
GenericAPIView + Mixins вручную
from rest_framework.generics import GenericAPIView
from rest_framework.mixins import ListModelMixin, CreateModelMixin
class BookListCreateView(ListModelMixin, CreateModelMixin, GenericAPIView):
queryset = Book.objects.all()
serializer_class = BookSerializer
def get(self, request, *args, **kwargs):
return self.list(request, *args, **kwargs)
def post(self, request, *args, **kwargs):
return self.create(request, *args, **kwargs)
ViewSet + Router
from rest_framework.viewsets import ModelViewSet, ReadOnlyModelViewSet
from rest_framework.routers import DefaultRouter
# Полный CRUD
class BookViewSet(ModelViewSet):
queryset = Book.objects.all()
serializer_class = BookSerializer
# Только чтение
class GenreViewSet(ReadOnlyModelViewSet):
queryset = Genre.objects.all()
serializer_class = GenreSerializer
# Router создаёт URL автоматически:
router = DefaultRouter()
router.register(r'books', BookViewSet)
router.register(r'genres', GenreViewSet)
urlpatterns = router.urls
# Генерирует:
# GET/POST /books/
# GET/PUT/PATCH/DELETE /books/{pk}/
# GET /genres/
# GET /genres/{pk}/
Статус-коды HTTP в DRF
| Константа | Код | Когда использовать |
HTTP_200_OK | 200 | GET, PUT, PATCH — успешно |
HTTP_201_CREATED | 201 | POST — объект создан |
HTTP_204_NO_CONTENT | 204 | DELETE — удалено, нет тела ответа |
HTTP_400_BAD_REQUEST | 400 | Ошибка валидации |
HTTP_404_NOT_FOUND | 404 | Объект не найден |
HTTP_405_METHOD_NOT_ALLOWED | 405 | Метод не разрешён |
from rest_framework import status
# Использование:
return Response(data, status=status.HTTP_201_CREATED)
return Response({'error': '...'}, status=status.HTTP_404_NOT_FOUND)