Фильтрация

⏱ 25 мин · 🧩 заданий: 5

Фильтрация вручную

Самый простой способ — читать параметры запроса в get_queryset():

class PostListView(generics.ListAPIView):
    serializer_class = PostSerializer

    def get_queryset(self):
        queryset = Post.published.select_related("author")
        author = self.request.query_params.get("author")
        tag = self.request.query_params.get("tag")
        if author:
            queryset = queryset.filter(author__username=author)
        if tag:
            queryset = queryset.filter(tags__name=tag)
        return queryset

GET /api/posts/?author=admin&tag=django

Работает, но для каждого фильтра — свой if. DRF предлагает бэкенды фильтрации.

django-filter

pip install django-filter
INSTALLED_APPS += ["django_filters"]

REST_FRAMEWORK = {
    ...
    "DEFAULT_FILTER_BACKENDS": ["django_filters.rest_framework.DjangoFilterBackend"],
}

Простые фильтры по точному совпадению:

class PostViewSet(viewsets.ModelViewSet):
    queryset = Post.objects.all()
    serializer_class = PostSerializer
    filterset_fields = ["status", "author"]

GET /api/posts/?status=PB&author=1

Свой FilterSet

Когда нужны диапазоны, поиск по подстроке, связанные поля:

import django_filters


class PostFilter(django_filters.FilterSet):
    published_after = django_filters.DateTimeFilter(field_name="publish", lookup_expr="gte")
    published_before = django_filters.DateTimeFilter(field_name="publish", lookup_expr="lte")
    title = django_filters.CharFilter(lookup_expr="icontains")
    author = django_filters.CharFilter(field_name="author__username")
    tag = django_filters.CharFilter(field_name="tags__name")

    class Meta:
        model = Post
        fields = ["status"]


class PostViewSet(viewsets.ModelViewSet):
    ...
    filterset_class = PostFilter

GET /api/posts/?published_after=2026-01-01&title=django&tag=orm

В Browsable API появится кнопка «Filters» с формой.

Поиск: SearchFilter

from rest_framework import filters


class PostViewSet(viewsets.ModelViewSet):
    ...
    filter_backends = [DjangoFilterBackend, filters.SearchFilter, filters.OrderingFilter]
    search_fields = ["title", "body", "author__username"]

GET /api/posts/?search=django — ищет подстроку (icontains) во всех полях из search_fields; несколько слов ищутся все сразу.

Модификаторы: "^title" — начинается с, "=title" — точное совпадение, "@body" — полнотекстовый поиск (PostgreSQL).

Сортировка: OrderingFilter

    ordering_fields = ["publish", "title"]
    ordering = ["-publish"]          # по умолчанию

GET /api/posts/?ordering=-publish — по убыванию даты, ?ordering=title,-publish — по нескольким полям.

Указывайте ordering_fields явно

Без ordering_fields клиент сможет сортировать по любому полю сериализатора — это может быть медленно и раскрыть лишнее.

Комбинирование

Все механизмы работают вместе:

GET /api/posts/?status=PB&search=django&ordering=-publish&page=2

Обратите внимание: если вы указываете filter_backends в классе, он заменяет DEFAULT_FILTER_BACKENDS, поэтому перечислите все нужные бэкенды.

Итог

  • Простейший фильтр — self.request.query_params в get_queryset().
  • django-filter: filterset_fields для простых случаев, FilterSet — для диапазонов и связей.
  • SearchFilter (?search=) и OrderingFilter (?ordering=) — поиск и сортировка.
  • filter_backends в классе заменяет настройки по умолчанию.

Практика решено 0 из 5

Вы не вошли — ответы проверяются, но прогресс не сохранится. Войти или зарегистрироваться.
Задание 1 Написать код

Переопределите get_queryset во PostListView: верните опубликованные посты, а если в параметрах запроса есть author, отфильтруйте по author__username.

Задание 2 Написать код

Подключите к PostViewSet фильтрацию django-filter, поиск и сортировку: filter_backends = DjangoFilterBackend, filters.SearchFilter, filters.OrderingFilter; filterset_fields = ["status", "author"], search_fields = ["title", "body"], ordering_fields = ["publish", "title"].

Задание 3 Один вариант ответа

Какой запрос вернёт посты, отсортированные по убыванию даты публикации (OrderingFilter)?

Задание 4 Ввод ответа

С каким параметром запроса работает SearchFilter по умолчанию? Напишите пример адреса для поиска «django» по /api/posts/.

Задание 5 Написать код

Опишите PostFilter (наследник django_filters.FilterSet) с фильтрами published_after (DateTimeFilter по полю publish, lookup gte) и title (CharFilter, lookup icontains). В Meta: модель Post, поля ["status"].

Войдите, чтобы отмечать пройденные уроки.