Фильтрация
Фильтрация вручную
Самый простой способ — читать параметры запроса в 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
Переопределите get_queryset во PostListView: верните опубликованные посты, а если в параметрах запроса
есть author, отфильтруйте по author__username.
class PostListView(generics.ListAPIView):
serializer_class = PostSerializer
def get_queryset(self):
queryset = Post.published.all()
author = self.request.query_params.get("author")
if author:
queryset = queryset.filter(author__username=author)
return queryset
Подключите к PostViewSet фильтрацию django-filter, поиск и сортировку:
filter_backends = DjangoFilterBackend, filters.SearchFilter, filters.OrderingFilter;
filterset_fields = ["status", "author"], search_fields = ["title", "body"], ordering_fields = ["publish", "title"].
from django_filters.rest_framework import DjangoFilterBackend
from rest_framework import filters, viewsets
class PostViewSet(viewsets.ModelViewSet):
queryset = Post.objects.all()
serializer_class = PostSerializer
filter_backends = [DjangoFilterBackend, filters.SearchFilter, filters.OrderingFilter]
filterset_fields = ["status", "author"]
search_fields = ["title", "body"]
ordering_fields = ["publish", "title"]
Какой запрос вернёт посты, отсортированные по убыванию даты публикации (OrderingFilter)?
С каким параметром запроса работает SearchFilter по умолчанию? Напишите пример адреса для поиска «django» по /api/posts/.
Опишите PostFilter (наследник django_filters.FilterSet) с фильтрами published_after
(DateTimeFilter по полю publish, lookup gte) и title (CharFilter, lookup icontains).
В Meta: модель Post, поля ["status"].
import django_filters
class PostFilter(django_filters.FilterSet):
published_after = django_filters.DateTimeFilter(field_name="publish", lookup_expr="gte")
title = django_filters.CharFilter(lookup_expr="icontains")
class Meta:
model = Post
fields = ["status"]
Войдите, чтобы отмечать пройденные уроки.