💻 Примеры — Урок 33
⚡ Ключевые примеры
# 1. lookup_field: поиск жанра по имени
class GenreDetailView(RetrieveUpdateDestroyAPIView):
queryset = Genre.objects.all()
serializer_class = GenreSerializer
lookup_field = 'name'
lookup_url_kwarg = 'genre_name'
# URL: path('genres/<str:genre_name>/', ...)
# GET /genres/comedy/ → {"id": 3, "name": "Comedy"}
# 2. get_object(): скрывать запрещённые книги
def get_object(self):
pk = self.kwargs.get('pk')
try:
book = self.queryset.get(pk=pk, is_banned=False)
except Book.DoesNotExist:
raise NotFound(f"Book {pk} not found or is banned.")
return book
# 3. get_serializer_context(): динамические поля
def get_serializer_context(self):
ctx = super().get_serializer_context()
ctx['include_related'] = self.request.query_params.get('include_related') == 'true'
return ctx
# 4. filter_backends: фильтрация + поиск + сортировка
class BookListView(ListAPIView):
filter_backends = [DjangoFilterBackend, SearchFilter, OrderingFilter]
filterset_fields = ['author', 'is_bestseller']
search_fields = ['title', 'author']
ordering_fields = ['price', 'published_date']
# GET /books/?search=Gatsby&ordering=-price
Пример 1: lookup_field и lookup_url_kwarg
Идентификация жанра по имени вместо pk.
models.py
from django.db import models
class Genre(models.Model):
name = models.CharField(max_length=100, unique=True)
def __str__(self):
return self.name
serializers.py
from rest_framework import serializers
from .models import Genre
class GenreSerializer(serializers.ModelSerializer):
class Meta:
model = Genre
fields = ['id', 'name']
views.py
from rest_framework.generics import RetrieveUpdateDestroyAPIView
from .models import Genre
from .serializers import GenreSerializer
class GenreDetailUpdateDeleteView(RetrieveUpdateDestroyAPIView):
queryset = Genre.objects.all()
serializer_class = GenreSerializer
lookup_field = 'name' # поле модели
lookup_url_kwarg = 'genre_name' # параметр URL
urls.py
from django.urls import path
from .views import GenreDetailUpdateDeleteView
urlpatterns = [
path('genres/<str:genre_name>/', GenreDetailUpdateDeleteView.as_view(),
name='genre-detail-update-delete'),
]
Результат
GET http://127.0.0.1:8000/genres/comedy/
HTTP 200 OK
{
"id": 3,
"name": "Comedy"
}
PATCH http://127.0.0.1:8000/genres/comedy/
{"name": "Comedy Films"}
DELETE http://127.0.0.1:8000/genres/comedy/
HTTP 204 No Content
Пример 2: Переопределение get_object()
Скрытие запрещённых книг через кастомный get_object().
models.py — добавление поля is_banned
from django.db import models
class Book(models.Model):
title = models.CharField(max_length=200)
author = models.CharField(max_length=100)
published_date = models.DateField()
price = models.DecimalField(max_digits=10, decimal_places=2,
null=True, blank=True)
is_bestseller = models.BooleanField(default=False)
genres = models.ManyToManyField('Genre', related_name='books')
is_banned = models.BooleanField(default=False) # новое поле
def __str__(self):
return self.title
views.py
from rest_framework.generics import RetrieveUpdateDestroyAPIView
from rest_framework.exceptions import NotFound
from .models import Book
from .serializers import BookSerializer
class BookDetailUpdateDeleteView(RetrieveUpdateDestroyAPIView):
queryset = Book.objects.all()
serializer_class = BookSerializer
def get_object(self):
pk = self.kwargs.get('pk')
try:
book = self.queryset.get(pk=pk, is_banned=False)
except Book.DoesNotExist:
raise NotFound(detail=f"Book with id '{pk}' not found or is banned.")
# Не забываем про object-level permissions
self.check_object_permissions(self.request, book)
return book
Результат
# Книга существует и не запрещена:
GET http://127.0.0.1:8000/books/1/
HTTP 200 OK {"id": 1, "title": "The Great Gatsby", ...}
# Книга запрещена (is_banned=True):
GET http://127.0.0.1:8000/books/5/
HTTP 404 Not Found
{"detail": "Book with id '5' not found or is banned."}
# Книги не существует:
GET http://127.0.0.1:8000/books/999/
HTTP 404 Not Found
{"detail": "Book with id '999' not found or is banned."}
Пример 3: get_serializer_context() с динамическими полями
Включение связанных данных (жанров) по запросу клиента.
views.py
from rest_framework.generics import ListAPIView
from .models import Book
from .serializers import BookSerializer
class BookListCreateView(ListAPIView):
queryset = Book.objects.all()
serializer_class = BookSerializer
def get_serializer_context(self):
context = super().get_serializer_context()
context['include_related'] = (
self.request.query_params.get('include_related', 'false').lower() == 'true'
)
return context
serializers.py
from rest_framework import serializers
from .models import Book
class BookSerializer(serializers.ModelSerializer):
class Meta:
model = Book
fields = '__all__'
def to_representation(self, instance):
representation = super().to_representation(instance)
if self.context.get('include_related'):
representation['genres'] = [genre.name for genre in instance.genres.all()]
else:
representation.pop('genres', None)
return representation
Результат
# С параметром include_related=true:
GET http://127.0.0.1:8000/books/?include_related=true
{
"id": 1,
"title": "The Great Gatsby",
"author": "F. Scott Fitzgerald",
"genres": ["Classic", "Fiction"],
...
}
# Без параметра (или include_related=false):
GET http://127.0.0.1:8000/books/
{
"id": 1,
"title": "The Great Gatsby",
"author": "F. Scott Fitzgerald"
// поле genres отсутствует
}
Пример 4: filter_backends — фильтрация, поиск, сортировка
Установка
pip install django-filter
settings.py
INSTALLED_APPS = [
...
'django_filters',
]
views.py
from rest_framework.generics import ListAPIView
from rest_framework import filters
from django_filters.rest_framework import DjangoFilterBackend
from .models import Book
from .serializers import BookSerializer
class BookListCreateView(ListAPIView):
queryset = Book.objects.all()
serializer_class = BookSerializer
filter_backends = [
DjangoFilterBackend,
filters.SearchFilter,
filters.OrderingFilter,
]
filterset_fields = ['author', 'publisher', 'is_bestseller']
search_fields = ['title', 'author']
ordering_fields = ['published_date', 'price']
Примеры запросов
# Фильтрация по автору (точное совпадение)
GET /books/?author=F. Scott Fitzgerald
→ все книги этого автора
# Поиск по заголовку и автору (подстрока)
GET /books/?search=Gatsby
→ книги, где title или author содержит "Gatsby"
# Сортировка по цене по возрастанию
GET /books/?ordering=price
# Сортировка по цене по убыванию
GET /books/?ordering=-price
# Только бестселлеры, отсортированные по дате
GET /books/?is_bestseller=true&ordering=-published_date
# Комбинирование: поиск + сортировка
GET /books/?search=classic&ordering=price