Фильтрация
источник:
filters.py
Фильтрация
Корневой QuerySet, предоставляемый менеджером, описывает все объекты в таблице базы данных. Однако обычно требуется выбрать только подмножество из полного набора объектов.
По умолчанию общие списочные представления DRF возвращают весь QuerySet
для менеджера модели. Часто требуется, чтобы API ограничивал количество элементов, возвращаемых QuerySet
.
Простейшим способом фильтрации QuerySet
любого представления, подкласса GenericAPIView
, является переопределение метода .get_queryset()
.
Переопределение этого метода позволяет настраивать QuerySet
, возвращаемый представлением, различными способами.
Фильтрация по текущему пользователю
Возможно, потребуется отфильтровать QuerySet
, чтобы возвращать только результаты, относящиеся к текущему аутентифицированному пользователю, сделавшему запрос.
Это можно сделать с помощью фильтрации по значению request.user
.
Например:
Фильтрация по URL
Другой стиль фильтрации может включать ограничение QuerySet
на основе некоторой части URL.
Например, если в конфигурации URL содержится запись следующего вида:
Затем вы можете написать представление, возвращающее QuerySet
покупок, отфильтрованный по имени пользователя в части URL:
Фильтрация по параметрам запроса
Следующим примером фильтрации исходного QuerySet может быть определение исходного QuerySet на основе параметров запроса в url.
Мы можем переопределить .get_queryset()
для работы с такими URL, как http://example.com/api/purchases?username=denvercoder9
, и фильтровать QuerySet только в том случае, если в URL включен параметр username
:
Общая фильтрация
Помимо возможности переопределения стандартного QuerySet, DRF также включает поддержку общих бэкендов фильтрации, которые позволяют легко строить сложные поисковые запросы и фильтры.
Общие фильтры также могут быть представлены в виде элементов управления HTML в API просмотра и API администрирования.
Настройка бэкендов фильтров
Бэкенды фильтров по умолчанию могут быть заданы глобально, с помощью параметра DEFAULT_FILTER_BACKENDS
. Например:
Вы также можете задать бэкенды фильтров для каждого вида или для каждого набора видов, используя класс GenericAPIView
, основанный на представлениях.
Фильтрация и поиск объектов
Обратите внимание, что если для представления настроен бэкэнд фильтрации, то он будет использоваться не только для фильтрации списочных представлений, но и для фильтрации QuerySet
, используемых для возврата одного объекта.
Например, если взять предыдущий пример и товар с идентификатором 4675
, то следующий URL будет либо возвращать соответствующий объект, либо возвращать ответ 404, в зависимости от того, были ли выполнены условия фильтрации для данного экземпляра товара:
Переопределение исходного QuerySet
Обратите внимание, что можно использовать и переопределенный .get_queryset()
, и общую фильтрацию, и все будет работать так, как ожидается. Например, если у Product
есть отношение "многие-ко-многим" с User
, названное purchase
, вы можете написать представление следующим образом:
Руководство по API
DjangoFilterBackend
Библиотека django-filter
включает класс DjangoFilterBackend
, который поддерживает высоконастраиваемую фильтрацию полей для DRF.
Чтобы использовать DjangoFilterBackend
, сначала установите django-filter
.
Затем добавьте 'django_filters'
в INSTALLED_APPS
Django:
Теперь необходимо либо добавить бэкэнд фильтра в настройки:
Или добавить бэкэнд фильтрации в отдельный View
или ViewSet
.
Если вам нужна простая фильтрация на основе равенства, вы можете установить атрибут filterset_fields
для представления или набора представлений, перечислив набор полей, по которым вы хотите осуществлять фильтрацию.
Это автоматически создаст класс FilterSet
для заданных полей и позволит выполнять такие запросы, как:
Для более сложных требований к фильтрации можно указать класс FilterSet
, который должен использоваться представлением. Более подробно о FilterSet
можно прочитать в документации django-filter. Также рекомендуется прочитать раздел Интеграция DRF.
SearchFilter
Класс SearchFilter
поддерживает простой поиск по одному параметру запроса и основан на функциональности поиска в админ-панели Django.
При использовании в состав Web-интерфейса API будет входить элемент управления SearchFilter
:
Класс SearchFilter
будет применяться только в том случае, если у представления установлен атрибут search_fields
. Атрибут search_fields
должен представлять собой список имен полей текстового типа в модели, например CharField
или TextField
.
Это позволит клиенту фильтровать элементы списка, задавая такие запросы, как:
Также можно выполнить связанный поиск по полю ForeignKey
или ManyToManyField
с помощью нотации двойного подчеркивания в API поиска:
Для полей JSONField и HStoreField можно осуществлять фильтрацию по вложенным значениям внутри структуры данных, используя ту же нотацию двойного подчеркивания:
По умолчанию в поиске используются частичные совпадения без учета регистра. Параметр search
может содержать несколько условий поиска, которые должны быть разделены пробелами и/или запятыми. Если используется несколько условий поиска, то объекты будут возвращены в списке только при совпадении всех указанных условий. Поиск может содержать цитируемые фразы с пробелами, каждая фраза рассматривается как один поисковый термин.
Поведение поиска может быть задано путем добавления префикса к именам полей в search_fields
одним из следующих символов (что эквивалентно добавлению __<lookup>
к полю):
Например:
По умолчанию параметр поиска называется 'search'
, но это можно переопределить с помощью параметра SEARCH_PARAM
.
Для динамического изменения полей поиска в зависимости от содержимого запроса можно подклассифицировать SearchFilter
и переопределить функцию get_search_fields()
. Например, следующий подкласс будет искать по title
, только если в запросе присутствует параметр запроса title_only
:
Более подробную информацию можно найти в документации Django.
OrderingFilter
Класс OrderingFilter
поддерживает простое упорядочивание результатов, управляемое параметрами запроса.
По умолчанию параметр запроса называется 'ordering'
, но это можно переопределить с помощью параметра ORDERING_PARAM
.
Например, чтобы упорядочить пользователей по имени пользователя:
Клиент может задать и обратный порядок, добавив к имени поля префикс '-', например, так:
Также может быть задано несколько порядков:
Указание того, какие поля могут быть использованы для упорядочивания
Рекомендуется явно указывать, какие поля API должен разрешать в фильтре упорядочивания. Это можно сделать, установив атрибут ordering_fields
на представлении, например, так:
Это позволяет предотвратить непредвиденную утечку данных, например, разрешить пользователям заказывать по хэш-полю пароли или другие конфиденциальные данные.
Если не указать атрибут orderering_fields
для представления, то класс фильтра будет по умолчанию позволять пользователю фильтровать по любым читаемым полям на сериализаторе, указанном атрибутом serializer_class
.
Если вы уверены, что используемый представлением Queryset
не содержит конфиденциальных данных, вы также можете явно указать, что представление должно разрешать упорядочивание по любому полю модели или агрегату Queryset
, используя специальное значение '__all__'
.
Указание порядка по умолчанию
Если у представления установлен атрибут ordering
, то он будет использоваться в качестве упорядочивания по умолчанию.
Обычно для этого используется параметр order_by
в исходном Queryset
, но использование параметра ordering
в представлении позволяет указать порядок таким образом, что он может быть автоматически передан в качестве контекста в шаблон рендеринга. Это позволяет автоматически отображать заголовки столбцов по-разному, если они используются для упорядочивания результатов.
Атрибут orderering
может быть как строкой, так и списком/кортежем строк.
Пользовательская общая фильтрация
Вы также можете предоставить свой собственный бэкэнд фильтрации или написать устанавливаемое приложение для использования другими разработчиками.
Для этого переопределите BaseFilterBackend
и переопределите метод .filter_queryset(self, request, queryset, view)
. Метод должен возвращать новый, отфильтрованный QuerySet
.
Помимо того, что клиенты могут выполнять поиск и фильтрацию, общие бэкенды фильтров могут быть полезны для ограничения того, какие объекты должны быть видны для каждого конкретного запроса или пользователя.
Пример
Например, может потребоваться ограничить доступ пользователей только к созданным ими объектам.
Мы могли бы добиться такого же поведения, переопределив get_queryset()
в представлениях, но использование бэкенда фильтров позволяет более просто добавить это ограничение к нескольким представлениям или применить его ко всему API.
Настройка интерфейса
Общие фильтры также могут представлять интерфейс в Web-интерфейсе API. Для этого необходимо реализовать метод to_html()
, который возвращает отрендеренное HTML-представление фильтра. Этот метод должен иметь следующую сигнатуру:
to_html(self, request, queryset, view)
.
Метод должен возвращать отрендеренную HTML-строку.
Пакеты сторонних производителей
Следующие пакеты сторонних производителей предоставляют дополнительные реализации фильтров.
Django-rest-framework-filters
django-rest-framework-filters работает совместно с классом DjangoFilterBackend
и позволяет легко создавать фильтры по отношениям, а также создавать несколько типов фильтров для поиска по заданному полю.
Djangorestframework-word-filter
djangorestframework-word-filter разработан как альтернатива filters.SearchFilter
, который будет искать полное слово в тексте, либо точное совпадение.
Django-url-filter
django-url-filter предоставляет безопасный способ фильтрации данных по удобным для человека URL-адресам. Он работает очень похоже на сериализаторы и поля DRF в том смысле, что они могут быть вложенными, за исключением того, что они называются filtersets
и filters
. Это обеспечивает простой способ фильтрации связанных данных. Кроме того, эта библиотека является универсальной, поэтому ее можно использовать для фильтрации других источников данных, а не только Django QuerySet
.
drf-url-filters
drf-url-filter - это простое Django-приложение для применения фильтров к Queryset
в ModelViewSet
чистым, простым и настраиваемым способом. Оно также поддерживает валидацию входящих параметров запроса и их значений. Для валидации входящих параметров запроса используется красивый python-пакет Voluptuous
. Самое приятное в Voluptuous
то, что вы можете определить свои собственные валидации в соответствии с требованиями к параметрам запроса.
Last updated