Руководство по API платформы Django REST (4): общие представления

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

Руководство по API платформы Django REST (1): запросы
Руководство по API платформы Django REST (2): ответы
Руководство по API платформы Django REST (3): представления
Руководство по API платформы Django REST (4): общие представления
Руководство по API платформы Django REST (5): наборы представлений
Руководство по API Django REST framework (6): Маршрутизация
Руководство по API платформы Django REST (7): анализ

Официальная оригинальная ссылка

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

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

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

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

взять каштан

Как правило, при использовании универсального представления необходимо создать подкласс представления и установить несколько свойств класса.

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

class UserList(generics.ListCreateAPIView):
    queryset = User.objects.all()
    serializer_class = UserSerializer
    permission_classes = (IsAdminUser,)

В более сложных случаях вы также можете переопределить различные методы в классе представления. Например.

class UserList(generics.ListCreateAPIView):
    queryset = User.objects.all()
    serializer_class = UserSerializer
    permission_classes = (IsAdminUser,)

    def list(self, request):
        # 注意使用`get_queryset()`而不是`self.queryset`
        queryset = self.get_queryset()
        serializer = UserSerializer(queryset, many=True)
        return Response(serializer.data)

Для очень простых случаев вы можете использовать.as_view()метод для передачи атрибутов класса. Например, ваш URLconf может содержать записи, подобные следующим:

url(r'^/users/', ListCreateAPIView.as_view(queryset=User.objects.all(), serializer_class=UserSerializer), name='user-list')

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

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

GenericAPIView

GenericAPIViewКласс наследуется от фреймворка REST.APIViewКласс, который добавляет общее поведение к стандартным представлениям списка и сведений.

Каждое встроенное конкретное универсальное представление создается путем добавленияGenericAPIViewКласс создается путем объединения одного или нескольких классов minxin друг с другом.

Атрибуты

основные настройки

Следующие свойства управляют основным поведением представления.

  • queryset- Набор запросов, используемый для возврата объектов из этого представления. Как правило, вы должны установить это свойство или переопределитьget_queryset()метод. Если вы переопределяете метод представления, в методе представления вы должны вызватьget_queryset()Это важно вместо прямого доступа к этому свойству! Поскольку REST будет внутреннеquerysetРезультат кэшируется для всех последующих запросов.
  • serializer_class- Классы сериализации для проверки и десериализации ввода и сериализации вывода. Как правило, вы должны установить это свойство или переопределитьget_serializer_class()метод.
  • lookup_field- Поля модели, используемые для поиска объектов для отдельных экземпляров модели. По умолчанию'pk'. Обратите внимание, что при использовании API с гиперссылками, если вам нужно использовать настраиваемые значения, необходимо убедиться, что в представлении API и классе сериализации установлено поле поиска.
  • lookup_url_kwarg- Аргументы ключевого слова URL для поиска объекта. Конфигурация URL должна содержать аргументы ключевого слова, соответствующие этому значению. Если не установлено, по умолчанию используется тот жеlookup_fieldтакое же значение.

Что касается последних двух параметров, я прилагаю сюда исходный код объектного запроса, чтобы все поняли.

Опустите часть кода для простоты понимания

def get_object(self):
	# 先获取数据集
    queryset = self.filter_queryset(self.get_queryset())
	# 拿到查询参数的 key
    lookup_url_kwarg = self.lookup_url_kwarg or self.lookup_field
	# 组装成 {key:value} 的形式
    filter_kwargs = {self.lookup_field: self.kwargs[lookup_url_kwarg]}
    # 查询
    obj = get_object_or_404(queryset, **filter_kwargs)
	# 最后返回
    return obj
нумерация страниц

При использовании с представлениями списка следующие свойства используются для управления разбиением на страницы.

  • pagination_class- Класс пагинации для использования при нумерации списков. Значение по умолчанию такое же, какDEFAULT_PAGINATION_CLASSНастройки одинаковые, т.е.rest_framework.pagination.PageNumberPagination. настраиватьpagination_class = NoneПейджинг будет отключен для этого представления.
фильтр
  • filter_backends- Список классов фильтров, используемых для фильтрации набора запросов. Значение по умолчанию такое же, какDEFAULT_FILTER_BACKENDSУстановите такое же значение.

метод

основной метод

get_queryset(self)

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

Этот метод всегда следует использовать вместо прямого доступаself.queryset, потому что REST внутриself.querysetРезультат кэшируется для всех последующих запросов.

Можно переопределить, чтобы обеспечить динамическое поведение, например возврат разных данных для разных пользовательских запросов.

Возьмите каштан:

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

get_object(self)

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

Можно переопределить, чтобы обеспечить более сложное поведение, например поиск объектов на основе нескольких kwargs URL.

Возьмите каштан:

def get_object(self):
    queryset = self.get_queryset()
    filter = {}
    for field in self.multiple_lookup_fields:
        filter[field] = self.kwargs[field]

    obj = get_object_or_404(queryset, **filter)
    self.check_object_permissions(self.request, obj)
    return obj

Обратите внимание: если ваш API не содержит каких-либо разрешений на уровне объекта, вы можете исключитьself.check_object_permissions, а просто изget_object_or_404Найдите возвращенный объект.

filter_queryset(self, queryset)

Учитывая набор запросов, отфильтруйте с помощью фильтра, чтобы вернуть новый набор запросов.

Возьмите каштан:

def filter_queryset(self, queryset):
    filter_backends = (CategoryFilter,)

    if 'geo_route' in self.request.query_params:
        filter_backends = (GeoRouteFilter, CategoryFilter)
    elif 'geo_point' in self.request.query_params:
        filter_backends = (GeoPointFilter, CategoryFilter)

    for backend in list(filter_backends):
        queryset = backend().filter_queryset(self.request, queryset, view=self)

    return queryset

get_serializer_class(self)

Возвращает класс, используемый для сериализации. вернуть по умолчаниюserializer_classАтрибуты.

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

Возьмите каштан:

def get_serializer_class(self):
    if self.request.user.is_staff:
        return FullAccountSerializer
    return BasicAccountSerializer
Сохраняйте и удаляйте хуки

Следующие методы предоставляются классом примеси, чтобы легко переопределить поведение сохранения и удаления объектов.

  • perform_create(self, serializer)- при сохранении нового экземпляра объектаCreateModelMixinперечислить.
  • perform_update(self, serializer)- при сохранении существующего экземпляра объектаUpdateModelMixinперечислить.
  • perform_destroy(self, instance)- При удалении экземпляра объектаDestroyModelMixinперечислить.

Эти хуки особенно полезны для установки свойств, которые неявно присутствуют в запросе, но не являются частью данных запроса. Например, вы можете установить свойства объектов на основе запрашивающего пользователя или на основе аргументов ключевого слова URL.

def perform_create(self, serializer):
    serializer.save(user=self.request.user)

Эти точки переопределения также особенно полезны для добавления поведения, которое происходит до или после сохранения объекта, например, отправка электронных писем с подтверждением или регистрация обновлений в журнале.

def perform_create(self, serializer):
    queryset = SignupRequest.objects.filter(user=self.request.user)
    if queryset.exists():
        raise ValidationError('You have already signed up')
    serializer.save(user=self.request.user)

Примечание. Эти методы заменяют устаревшую версию 2.x.pre_save,post_save,pre_deleteиpost_deleteметоды, которых уже нет.

Другие методы

Обычно нет необходимости переопределять следующие методы, но если вы используетеGenericAPIViewНапишите пользовательские представления, вам может понадобиться вызвать их.

  • get_serializer_context(self)- Возвращает словарь, содержащий любой дополнительный контекст, который должен быть предоставлен для сериализации. По умолчанию включает'request', 'view'и'format'ключ.
  • get_serializer(self, instance=None, data=None, many=False, partial=False)- Возвращает экземпляр сериализатора.
  • get_paginated_response(self, data)- вернуть стиль пагинацииResponseобъект.
  • paginate_queryset(self, queryset)- разбивает набор запросов на страницы по мере необходимости или возвращает объект страницы, или если разбиение по страницам не настроено для этого представленияNone.
  • filter_queryset(self, queryset)- Учитывая набор запросов, отфильтровать с помощью фильтра, возвращая новый набор запросов.

Mixins

Класс mixin используется для предоставления операций для базового поведения представления. Обратите внимание, что класс примеси предоставляет методы действия вместо прямого определения методов обработчика, таких как.get()и.post(). Это позволяет более гибко комбинировать поведение.

Доступ к классу миксина можно получить изrest_framework.mixinsимпортировать в.

ListModelMixin

обеспечить.list(request, *args, **kwargs)метод, реализующий вывод набора запросов.

Возвращает, если набор запросов заполнен200 OKОтвет с сериализованным представлением набора запросов в качестве тела ответа. Данные ответа могут быть разбиты на страницы.

CreateModelMixin

поставка.create(request, *args, **kwargs)методы, реализующие создание и сохранение новых экземпляров модели.

Если объект был создан, он вернет201 CreatedОтвет с сериализованным представлением этого объекта в качестве тела ответа. Если представление содержит ключ с именем url, ответLocationзаголовок будет заполнен этим значением.

Вернется, если данные запроса, предоставленные для создания объекта, недействительны.400 Bad RequestОтвет с подробностями об ошибке в качестве тела ответа.

RetrieveModelMixin

поставка.retrieve(request, *args, **kwargs)метод, реализующий возврат существующего экземпляра модели в ответе.

Возвращает, если объект может быть получен200 OKОтвет с сериализованным представлением объекта в виде тела ответа. В противном случае он вернет404 Not Found.

UpdateModelMixin

поставка.update(request, *args, **kwargs)метод, реализующий обновление и сохранение существующих экземпляров модели. также обеспечивает.partial_update(request, *args, **kwargs)метод, который аналогичен методу обновления, за исключением того, что все обновляемые поля являются необязательными. Это позволяет поддерживать HTTPPATCHпросить.

Возвращает, если объект был успешно обновлен200 OKОтвет с сериализованным представлением объекта в виде тела ответа.

Вернется, если запрошенные данные, предоставленные для обновления объекта, недействительны.400 Bad RequestОтвет с подробностями об ошибке в качестве тела ответа.

DestroyModelMixin

обеспечить.destroy(request, *args, **kwargs)метод для удаления существующего экземпляра модели.

Если объект был удален, возвращает204 No Content, иначе он вернет404 Not Found.

Список встроенных классов представлений

Следующие классы являются конкретными универсальными представлениями. Как правило, вы должны использовать их, если вам не нужно специальное поведение.

Доступ к этим классам представлений можно получить изrest_framework.genericsимпортировать в.

CreateAPIView

Только создание экземпляра.

обеспечитьpostМетод обработки запроса.

Унаследовано от:GenericAPIView, CreateModelMixin

ListAPIView

Используется только для чтения списка экземпляров модели.

обеспечитьgetМетод обработки запроса.

Унаследовано от:GenericAPIView, ListModelMixin

RetrieveAPIView

Используется только для запроса одного экземпляра модели.

обеспечитьgetМетод обработки запроса.

Унаследовано от:GenericAPIView, RetrieveModelMixin

DestroyAPIView

Используется только для удаления одного экземпляра модели.

обеспечитьdeleteМетод обработки запроса.

Унаследовано от:GenericAPIView, DestroyModelMixin

UpdateAPIView

Используется только для обновления одного экземпляра модели.

поставкаputиpatchМетод обработки запроса.

Унаследовано от:GenericAPIView, UpdateModelMixin

ListCreateAPIView

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

поставкаgetиpostМетод обработки запроса.

Унаследовано от:GenericAPIView, ListModelMixin,CreateModelMixin

RetrieveUpdateAPIView

Может как запрашивать, так и обновлять один экземпляр

поставкаget,putиpatchМетод обработки запроса.

Унаследовано от:GenericAPIView, RetrieveModelMixin,UpdateModelMixin

RetrieveDestroyAPIView

Как запрашивать, так и удалять отдельные экземпляры

поставкаgetиdeleteМетод обработки запроса.

Унаследовано от:GenericAPIView, RetrieveModelMixin,DestroyModelMixin

RetrieveUpdateDestroyAPIView

В то же время поддержка запроса, обновления, удаления

поставкаget,put,patchиdeleteМетод обработки запроса.

Унаследовано от:GenericAPIView, RetrieveModelMixin,UpdateModelMixin,DestroyModelMixin

Пользовательский универсальный класс представления

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

пользовательские миксины

Например, если вам нужно найти объекты на основе нескольких полей в конфигурации URL, вы можете создать класс миксина.

Возьмите каштан:

class MultipleFieldLookupMixin(object):
    """
    将此 mixin 应用于任何视图或视图集以获取多个字段过滤
    基于`lookup_fields`属性,而不是默认的单个字段过滤。
    """
    def get_object(self):
        queryset = self.get_queryset()             # 获取基本的查询集
        queryset = self.filter_queryset(queryset)  # 使用过滤器
        filter = {}
        for field in self.lookup_fields:
            if self.kwargs[field]: # 忽略空字段
                filter[field] = self.kwargs[field]
        obj = get_object_or_404(queryset, **filter)  # 查找对象
        self.check_object_permissions(self.request, obj)
        return obj

Затем примесь можно применить к представлению или набору представлений всякий раз, когда необходимо применить пользовательское поведение.

class RetrieveUserView(MultipleFieldLookupMixin, generics.RetrieveAPIView):
    queryset = User.objects.all()
    serializer_class = UserSerializer
    lookup_fields = ('account', 'username')

Использование пользовательских миксинов — хороший вариант, если вам нужно использовать настраиваемое поведение.

пользовательский базовый класс

Если вы используете миксин в нескольких представлениях, вы можете сделать еще один шаг, создав собственный набор базовых представлений, а затем использовать их в своем проекте. Например:

class BaseRetrieveView(MultipleFieldLookupMixin,
                       generics.RetrieveAPIView):
    pass

class BaseRetrieveUpdateDestroyView(MultipleFieldLookupMixin,
                                    generics.RetrieveUpdateDestroyAPIView):
    pass

Использование настраиваемого базового класса — хороший вариант, если настраиваемое поведение всегда необходимо повторно использовать в большом количестве представлений по всему проекту.