Руководство по API платформы Django REST (16): фильтрация

задняя часть Python Django

Официальная оригинальная ссылка
Эта серия статей адрес github
Пожалуйста, укажите источник

фильтр

Поведение по умолчанию общих представлений списка платформы REST заключается в том, чтобы вернуть весь набор запросов из диспетчера моделей. Часто вам нужно, чтобы API ограничивал элементы, возвращаемые набором запросов.

фильтрGenericAPIViewСамый простой способ создать подкласс набора запросов — переопределить.get_queryset()метод.

Переопределение этого метода позволяет настраивать набор запросов, возвращаемый представлением, разными способами.

Фильтровать по текущему пользователю

Вам может потребоваться отфильтровать набор запросов, чтобы гарантировать, что возвращаются только результаты, относящиеся к запросам, сделанным пользователем, прошедшим проверку подлинности.

ты можешь основатьrequest.userЭто делается путем фильтрации по значению .

Например:

from myapp.models import Purchase
from myapp.serializers import PurchaseSerializer
from rest_framework import generics

class PurchaseList(generics.ListAPIView):
    serializer_class = PurchaseSerializer

    def get_queryset(self):
        """
        This view should return a list of all the purchases
        for the currently authenticated user.
        """
        user = self.request.user
        return Purchase.objects.filter(purchaser=user)

Фильтровать по URL

Другой способ фильтрации может заключаться в ограничении набора запросов на основе части URL-адреса.

Например, если ваша конфигурация URL-адреса содержит такую ​​запись:

url('^purchases/(?P<username>.+)/$', PurchaseList.as_view()),

Затем вы можете написать представление, которое возвращает набор запросов о покупках, отфильтрованных по имени пользователя в URL-адресе:

class PurchaseList(generics.ListAPIView):
    serializer_class = PurchaseSerializer

    def get_queryset(self):
        """
        This view should return a list of all the purchases for
        the user as determined by the username portion of the URL.
        """
        username = self.kwargs['username']
        return Purchase.objects.filter(purchaser__username=username)

Фильтр по параметрам запроса

Последний пример фильтрации исходного набора запросов — определение исходного набора запросов на основе параметров запроса в URL-адресе.

мы можем покрыть.get_queryset()обращаться с такими вещами, какhttp://example.com/api/purchases?username=denvercoder9URL, и только если URL содержитusernameНабор запросов фильтруется только в том случае, если параметр:

class PurchaseList(generics.ListAPIView):
    serializer_class = PurchaseSerializer

    def get_queryset(self):
        """
        Optionally restricts the returned purchases to a given user,
        by filtering against a `username` query parameter in the URL.
        """
        queryset = Purchase.objects.all()
        username = self.request.query_params.get('username', None)
        if username is not None:
            queryset = queryset.filter(purchaser__username=username)
        return queryset

Универсальный фильтр

В дополнение к возможности переопределить набор запросов по умолчанию, среда REST также включает поддержку универсальной серверной части фильтрации, что позволяет легко создавать сложные поиски и фильтры.

Общие фильтры также могут отображать себя как элементы управления HTML в доступном для просмотра API и API администратора.

Filter Example

установить серверную часть фильтра

можно использоватьDEFAULT_FILTER_BACKENDSнастройка Глобально устанавливает серверную часть фильтра по умолчанию. Например.

REST_FRAMEWORK = {
    'DEFAULT_FILTER_BACKENDS': ('django_filters.rest_framework.DjangoFilterBackend',)
}

Вы также можете использоватьGenericAPIViewПредставление класса, которое устанавливает серверную часть фильтра для каждого представления или набора представлений.

import django_filters.rest_framework
from django.contrib.auth.models import User
from myapp.serializers import UserSerializer
from rest_framework import generics

class UserListView(generics.ListAPIView):
    queryset = User.objects.all()
    serializer_class = UserSerializer
    filter_backends = (django_filters.rest_framework.DjangoFilterBackend,)

Фильтрация и поиск объектов

Обратите внимание, что если представление настроено с фильтрующей серверной частью, помимо фильтрации представления списка, оно также будет использоваться для фильтрации наборов запросов, которые возвращают один объект.

Например, согласно предыдущему примеру и идентификатор4675, следующий URL-адрес вернет соответствующий объект или ответ 404, в зависимости от того, соответствует ли данный экземпляр продукта критериям фильтра:

http://example.com/api/products/4675/?category=clothing&max_price=10.00

Переопределить исходный набор запросов

Обратите внимание, что вы можете переопределить оба.get_queryset()и общую фильтрацию, и все будет работать как положено. Например, если продукты имеют отношения «многие ко многим» с пользователями, вы можете написать представление, которое выглядит следующим образом:

class PurchasedProductsList(generics.ListAPIView):
    """
    Return a list of all the products that the authenticated
    user has ever purchased, with optional filtering.
    """
    model = Product
    serializer_class = ProductSerializer
    filter_class = ProductFilter

    def get_queryset(self):
        user = self.request.user
        return user.purchase_set.all()

Справочник по API

DjangoFilterBackend

django-filterБиблиотека содержитDjangoFilterBackendКласс, который позволяет платформе REST настраивать фильтрацию полей.

нужно использоватьDjangoFilterBackend, первая установкаdjango-filter. потомdjango_filtersдобавлено в ДжангоINSTALLED_APPSсередина

pip install django-filter

Теперь вы должны добавить бэкенд фильтра в настройки:

REST_FRAMEWORK = {
    'DEFAULT_FILTER_BACKENDS': ('django_filters.rest_framework.DjangoFilterBackend',)
}

Или добавьте серверные части фильтра к одному представлению или набору представлений.

from django_filters.rest_framework import DjangoFilterBackend

class UserListView(generics.ListAPIView):
    ...
    filter_backends = (DjangoFilterBackend,)

Если вам просто нужна простая фильтрация на основе уравнений, вы можете установить ее в представлении или наборе представлений.filter_fieldsсвойство, в котором перечислены наборы полей, по которым вы хотите отфильтровать.

class ProductList(generics.ListAPIView):
    queryset = Product.objects.all()
    serializer_class = ProductSerializer
    filter_backends = (DjangoFilterBackend,)
    filter_fields = ('category', 'in_stock')

Это автоматически создастFilterSetclass и позволяет вам делать такие запросы, как:

http://example.com/api/products?category=clothing&in_stock=True

Для более сложных требований к фильтрации вы должны указать в представленииFilterSetсвоего рода. ты сможешьдокументация по django-фильтручитать оFilterSetЧтобы получить больше информации. Также рекомендуем прочитатьDRF integration.

SearchFilter

SearchFilterКласс поддерживает простой поиск на основе одного параметра запроса и основан на возможностях поиска администратора Django.

При использовании доступный для просмотра API будет содержатьSearchFilterЭлементы управления:

Search Filter

SearchFilterКласс будет работать, только если представление имеетsearch_fieldsПрименяется в случае набора свойств.search_fieldsСвойства должны быть списком имен полей текстового типа в модели, например.CharFieldилиTextField.

class UserListView(generics.ListAPIView):
    queryset = User.objects.all()
    serializer_class = UserSerializer
    filter_backends = (filters.SearchFilter,)
    search_fields = ('username', 'email')

Это позволит клиентам фильтровать элементы в списке, запрашивая, например:

http://example.com/api/users?search=russell

Вы также можете выполнить связанный поиск для ForeignKey или ManyToManyField, используя нотацию двойного подчеркивания API поиска:

search_fields = ('username', 'email', 'profile__profession')

По умолчанию поиск будет использовать частичные совпадения без учета регистра. Параметры поиска могут содержать несколько условий поиска, которые должны быть разделены пробелами и/или запятыми. Если используется несколько критериев поиска, объекты будут возвращены в список только в том случае, если все предоставленные критерии совпадают.

Поведение при поиске может быть достигнуто добавлением различных символов передsearch_fieldsограничить.

  • '^' соответствует начальной части.
  • '=' точно соответствует.
  • '@' исследовать все. (В настоящее время поддерживается только серверная часть MySQL для Django.)
  • '$' Обычное совпадение.

Например:

search_fields = ('=username', '=email')

По умолчанию параметры поиска называются'search', но это может бытьSEARCH_PARAMнастройка переопределения.

Подробнее см.Документация Джанго.


OrderingFilter

OrderingFilterКласс поддерживает простые параметры запроса для управления порядком результатов.

Ordering Filter

По умолчанию параметры запроса называются'ordering', но это может бытьORDERING_PARAMнастройка переопределения.

Например, чтобы отсортировать пользователей по имени пользователя:

http://example.com/api/users?ordering=username

Клиенты также могут указывать обратный порядок, добавляя к имени поля префикс «-», как показано ниже:

http://example.com/api/users?ordering=-username 

Также можно указать несколько видов:

http://example.com/api/users?ordering=account,username

Указывает, какие поля можно сортировать по

Рекомендуется явно указать, какие поля API должен разрешать в фильтрах сортировки. Вы можете сделать это, установивordering_fieldsсделать это следующим образом:

class UserListView(generics.ListAPIView):
    queryset = User.objects.all()
    serializer_class = UserSerializer
    filter_backends = (filters.OrderingFilter,)
    ordering_fields = ('username', 'email')

Это помогает предотвратить случайную утечку данных, например позволяя пользователям сортировать на основе хэш-полей паролей или других конфиденциальных данных.

Если вы не укажете в представленииordering_fieldsатрибут, класс фильтра по умолчанию позволит пользователям фильтровать поserializer_classЛюбые доступные для чтения поля в сериализованном классе, указанном свойством.

Если вы уверены, что набор запросов, используемый представлением, не содержит конфиденциальных данных, вы также можете использовать специальное значение'__all__'Явное указание представления позволяет выполнять сортировку по любому полю модели или агрегату набора запросов.

class BookingsListView(generics.ListAPIView):
    queryset = Booking.objects.all()
    serializer_class = BookingSerializer
    filter_backends = (filters.OrderingFilter,)
    ordering_fields = '__all__'

Укажите порядок по умолчанию

Если установлено в представленииorderingсвойство, оно будет использоваться как порядок по умолчанию.

Обычно вы должны сделать это, установив в начальном наборе запросовorder_byконтролировать это, но с помощьюorderingможно указать метод упорядочения, который затем может быть автоматически передан в качестве контекста отображаемому шаблону. Это может автоматически отображать заголовки столбцов, если они используются для сортировки результатов.

class UserListView(generics.ListAPIView):
    queryset = User.objects.all()
    serializer_class = UserSerializer
    filter_backends = (filters.OrderingFilter,)
    ordering_fields = ('username', 'email')
    ordering = ('username',)

orderingСвойство может быть строкой или списком (кортежем) строк.


DjangoObjectPermissionsFilter

DjangoObjectPermissionsFilterнаправленный наdjango-guardianПакеты используются вместе с дополнительной настройкой'view'разрешение. Фильтр гарантирует, что набор запросов возвращает только те объекты, для просмотра которых у пользователя есть соответствующие права.

если вы используетеDjangoObjectPermissionsFilter, то вам также может понадобиться добавить соответствующие классы разрешений для объектов, чтобы пользователи могли работать с экземпляром только в том случае, если у них есть соответствующие разрешения на объекты. Самый простой способ сделать это - наследоватьDjangoObjectPermissionsи дляperms_mapатрибут добавлен'view'разрешения.

использоватьDjangoObjectPermissionsFilterиDjangoObjectPermissionsПолный пример может выглядеть так.

permissions.py:

class CustomObjectPermissions(permissions.DjangoObjectPermissions):
    """
    Similar to `DjangoObjectPermissions`, but adding 'view' permissions.
    """
    perms_map = {
        'GET': ['%(app_label)s.view_%(model_name)s'],
        'OPTIONS': ['%(app_label)s.view_%(model_name)s'],
        'HEAD': ['%(app_label)s.view_%(model_name)s'],
        'POST': ['%(app_label)s.add_%(model_name)s'],
        'PUT': ['%(app_label)s.change_%(model_name)s'],
        'PATCH': ['%(app_label)s.change_%(model_name)s'],
        'DELETE': ['%(app_label)s.delete_%(model_name)s'],
    }

views.py:

class EventViewSet(viewsets.ModelViewSet):
    """
    Viewset that only lists events if user has 'view' permissions, and only
    allows operations on individual events if user has appropriate 'view', 'add',
    'change' or 'delete' permissions.
    """
    queryset = Event.objects.all()
    serializer_class = EventSerializer
    filter_backends = (filters.DjangoObjectPermissionsFilter,)
    permission_classes = (myapp.permissions.CustomObjectPermissions,)

Пользовательский общий фильтр

Вы также можете предоставить свой собственный базовый фильтр или написать устанавливаемое приложение, которое могут использовать другие разработчики.

Для этого наследуйтеBaseFilterBackend, и перезаписать.filter_queryset(self, request, queryset, view)метод. Метод должен возвращать новый отфильтрованный набор запросов.

В дополнение к предоставлению клиентам возможности выполнять поиск и фильтрацию, базовая часть общего фильтра может использоваться для ограничения того, какие объекты должны быть видны для данного запроса или пользователя.

взять каштан

Вы можете разрешить пользователям видеть только созданные ими объекты.

class IsOwnerFilterBackend(filters.BaseFilterBackend):
    """
    Filter that only allows users to see their own objects.
    """
    def filter_queryset(self, request, queryset, view):
        return queryset.filter(owner=request.user)

Мы можем сделать это, переопределивget_queryset()для достижения того же поведения, но использование бэкенда фильтра позволяет вам более легко добавить это ограничение к нескольким представлениям или применить его ко всему API.

настраиваемый интерфейс

Общие фильтры также могут отображать интерфейсы в доступном для просмотра API. Для этого следует реализоватьto_html()метод, возвращающий обработанное HTML-представление фильтра. Этот метод должен иметь следующую подпись:

to_html(self, request, queryset, view)

Метод должен возвращать отображаемую строку HTML.

Pagination & schemas

путем реализацииget_schema_fields()метод, вы также можете сделать элементы управления фильтрами доступными для автоматического создания схемы, предоставляемой инфраструктурой REST. Этот метод должен иметь следующую подпись:

get_schema_fields(self, view)

Метод должен возвращатьcoreapi.FieldСписок экземпляров.