🔖 Справочник — Урок 33

← К оглавлению урока

⚡ Быстрый справочник

# lookup_field + lookup_url_kwarg (views.py)
class MyView(RetrieveUpdateDestroyAPIView):
    lookup_field = 'slug'           # поле модели
    lookup_url_kwarg = 'my_slug'    # параметр URL

# urls.py
path('items/<str:my_slug>/', MyView.as_view())

# get_object() — переопределение
def get_object(self):
    pk = self.kwargs.get('pk')
    try:
        obj = self.queryset.get(pk=pk, is_active=True)
    except MyModel.DoesNotExist:
        raise NotFound("Not found.")
    self.check_object_permissions(self.request, obj)  # не забыть!
    return obj

# get_serializer_context()
def get_serializer_context(self):
    context = super().get_serializer_context()
    context['my_flag'] = self.request.query_params.get('flag') == 'true'
    return context

# filter_backends — установка и настройка
pip install django-filter
# settings.py: INSTALLED_APPS += ['django_filters']

class MyListView(ListAPIView):
    filter_backends = [DjangoFilterBackend, filters.SearchFilter,
                       filters.OrderingFilter]
    filterset_fields = ['status', 'author']
    search_fields = ['title', 'description']
    ordering_fields = ['created_at', 'price']

# Параметры запроса
?author=Ivanov          # точная фильтрация
?search=django          # поиск по search_fields
?ordering=price         # сортировка по возрастанию
?ordering=-price        # сортировка по убыванию

Таблица атрибутов GenericAPIView (урок 33)

Атрибут / МетодТипОписаниеЗначение по умолчанию
lookup_field str Поле модели для поиска объекта 'pk'
lookup_url_kwarg str | None Параметр URL для значения lookup_field None (совпадает с lookup_field)
get_object() метод Возвращает один объект; переопределяется для кастомной логики Стандартный поиск по lookup_field
get_serializer_context() метод Возвращает словарь контекста для сериализатора {'request', 'format', 'view'}
filter_backends list Список классов фильтрации [] (или из DEFAULT_FILTER_BACKENDS)
filterset_fields list Поля для точной фильтрации (DjangoFilterBackend)
search_fields list Поля для текстового поиска (SearchFilter)
ordering_fields list Поля для сортировки (OrderingFilter)

lookup_field и lookup_url_kwarg — синтаксис

# 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 = [
    # параметр <str:genre_name> должен совпадать с lookup_url_kwarg
    path('genres/<str:genre_name>/', GenreDetailUpdateDeleteView.as_view(),
         name='genre-detail-update-delete'),
]

get_object() — шаблон переопределения

# views.py
from rest_framework.generics import RetrieveUpdateDestroyAPIView
from rest_framework.exceptions import NotFound
from .models import Book

class BookDetailUpdateDeleteView(RetrieveUpdateDestroyAPIView):
    queryset = Book.objects.all()
    serializer_class = BookSerializer

    def get_object(self):
        pk = self.kwargs.get('pk')
        try:
            obj = self.queryset.get(pk=pk, is_banned=False)
        except Book.DoesNotExist:
            raise NotFound(detail=f"Book with id '{pk}' not found or is banned.")
        # Явный вызов проверки разрешений на уровне объекта
        self.check_object_permissions(self.request, obj)
        return obj

get_serializer_context() — шаблон

# views.py
class MyView(ListAPIView):
    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
class MySerializer(serializers.ModelSerializer):
    def to_representation(self, instance):
        rep = super().to_representation(instance)
        if self.context.get('include_related'):
            rep['genres'] = [g.name for g in instance.genres.all()]
        else:
            rep.pop('genres', None)
        return rep

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 BookListView(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']

Параметры запроса

ПараметрБэкендПример
?field=valueDjangoFilterBackend?author=Tolstoy
?search=textSearchFilter?search=war
?ordering=fieldOrderingFilter?ordering=price
?ordering=-fieldOrderingFilter (убывание)?ordering=-price