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

задняя часть 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): анализ

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

Набор видов

После того, как маршрутизация решила, какой контроллер использовать для запроса, контроллер отвечает за понимание запроса и создание соответствующего вывода.
Документация по Ruby on Rails

Фреймворк Django REST позволяет объединить логику набора связанных представлений вViewSetв классе. В других фреймворках вы можете найти концептуально похожие реализации под названием «Ресурсы» или «Контроллеры».

ViewSetКласс — это просто представление на основе класса, он не предоставляет никаких методов обработки, таких как.get()или.post(), вместо этого предоставив что-то вроде.list()и.create()такие операции.

ViewSetтолько в использовании.as_view()Выполните какое-либо действие, когда метод привязан к окончательному представлению.

Как правило, вместо явной регистрации представлений в наборе представлений в urlconf вы регистрируете набор представлений в классе маршрутизатора, который автоматически определяет для вас urlconf.

взять каштан

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

from django.contrib.auth.models import User
from django.shortcuts import get_object_or_404
from myapps.serializers import UserSerializer
from rest_framework import viewsets
from rest_framework.response import Response

class UserViewSet(viewsets.ViewSet):

    def list(self, request):
        queryset = User.objects.all()
        serializer = UserSerializer(queryset, many=True)
        return Response(serializer.data)

    def retrieve(self, request, pk=None):
        queryset = User.objects.all()
        user = get_object_or_404(queryset, pk=pk)
        serializer = UserSerializer(user)
        return Response(serializer.data)

При желании это представление можно объединить в два отдельных представления следующим образом:

user_list = UserViewSet.as_view({'get': 'list'})
user_detail = UserViewSet.as_view({'get': 'retrieve'})

Обычно мы этого не делаем, а регистрируем набор представлений на маршрутизаторе и разрешаем автоматическую генерацию urlconf.

from myapp.views import UserViewSet
from rest_framework.routers import DefaultRouter

router = DefaultRouter()
router.register(r'users', UserViewSet, base_name='user')
urlpatterns = router.urls

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

class UserViewSet(viewsets.ModelViewSet):
    """
    用于查看和编辑用户实例的视图。
    """
    serializer_class = UserSerializer
    queryset = User.objects.all()

использоватьViewSetЕсть два основных преимущества использования класса View по аналогии.

  • Дублирующаяся логика может быть объединена в один класс. В приведенном выше примере нам нужно указать набор запросов только один раз, и он будет использоваться в нескольких представлениях.
  • Используя маршрутизаторы, нам больше не нужно обрабатывать вашу конфигурацию URL.

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

Управление наборами представлений

Маршруты по умолчанию, включенные в структуру REST, будут предоставлять маршруты для стандартного набора действий стиля создания/получения/обновления/удаления следующим образом:

class UserViewSet(viewsets.ViewSet):
    """
    这些方法将由路由器负责处理。

    如果要使用后缀,请确保加上 `format = None` 关键字参数
    """

    def list(self, request):
        pass

    def create(self, request):
        pass

    def retrieve(self, request, pk=None):
        pass

    def update(self, request, pk=None):
        pass

    def partial_update(self, request, pk=None):
        pass

    def destroy(self, request, pk=None):
        pass

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

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

def get_permissions(self):
    """
    实例化并返回此视图所需的权限列表。
    """
    if self.action == 'list':
        permission_classes = [IsAuthenticated]
    else:
        permission_classes = [IsAdmin]
    return [permission() for permission in permission_classes]

Отметить дополнительное поведение маршрутизации

Если вам нужно направить определенный метод, вы можете использовать@detail_routeили@list_routeдекоратор для украшения.

@detail_routeДекоратор содержит в своем шаблоне URLpk, чтобы поддерживать методы, которые необходимо получить один экземпляр.@list_routeМодификатор подходит для метода работы со списком объектов.

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

from django.contrib.auth.models import User
from rest_framework import status
from rest_framework import viewsets
from rest_framework.decorators import detail_route, list_route
from rest_framework.response import Response
from myapp.serializers import UserSerializer, PasswordSerializer

class UserViewSet(viewsets.ModelViewSet):
    """
    提供标准操作的视图集
    """
    queryset = User.objects.all()
    serializer_class = UserSerializer

    @detail_route(methods=['post'])
    def set_password(self, request, pk=None):
        user = self.get_object()
        serializer = PasswordSerializer(data=request.data)
        if serializer.is_valid():
            user.set_password(serializer.data['password'])
            user.save()
            return Response({'status': 'password set'})
        else:
            return Response(serializer.errors,
                            status=status.HTTP_400_BAD_REQUEST)

    @list_route()
    def recent_users(self, request):
        recent_users = User.objects.all().order('-last_login')

        page = self.paginate_queryset(recent_users)
        if page is not None:
            serializer = self.get_serializer(page, many=True)
            return self.get_paginated_response(serializer.data)

        serializer = self.get_serializer(recent_users, many=True)
        return Response(serializer.data)

Кроме того, декоратор может задать дополнительные параметры для просмотра маршрута. Например...

    @detail_route(methods=['post'], permission_classes=[IsAdminOrIsSelf])
    def set_password(self, request, pk=None):
       ...

Маршруты этих декораторов по умолчаниюGETзапрос, но также может использоватьmethodsПараметры принимают другие методы HTTP. Например:

    @detail_route(methods=['post', 'delete'])
    def unset_password(self, request, pk=None):
       ...

Эти две новые операции будут URL-адресами^users/{pk}/set_password/$и^users/{pk}/unset_password/$начальство.

Действие прыгать

Если вам нужно получить URL-адрес действия, используйте.reverse_action()метод. Это.reverse()Удобная оболочка, которая автоматически передает объект запроса представления иurl_nameи.basenameАтрибуты крючки.

Пожалуйста, обрати внимание,basenameвViewSetПредоставляется роутером при регистрации. Если вы не используете маршрутизатор, вы должны предоставить.as_view()методbasenameпараметр.

Используя пример из предыдущего раздела:

>>> view.reverse_action('set-password', args=['1'])
'http://localhost:8000/api/users/1/set_password'

url_nameПараметр должен быть таким же, как@list_routeи@detail_routeТот же аргумент декоратора совпадает. Кроме того, это можно использовать для инвертирования значения по умолчанию.listиdetailмаршрутизация.

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

ViewSet

ViewSetкласс наследуется отAPIView. Вы можете использовать любой из стандартных свойств, таких какpermission_classes,authentication_classes) для управления политикой API в представлении.

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

GenericViewSet

GenericViewSetкласс наследуется отGenericAPIView, и укажите значение по умолчаниюget_object,get_querysetМетоды и другие базовые функции общего представления, но по умолчанию операции не включены.

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

ModelViewSet

ModelViewSetкласс наследуется отGenericAPIView, и включать реализации различных операций, смешивая поведение различных классов примесей.

ModelViewSetПредоставляемые операции.list() , .retrieve() , .create() , .update() , .partial_update(), и.destroy().

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

так какModelViewSetкласс наследуется отGenericAPIViewСледовательно, часто необходимо обеспечить хотя быquerysetиserializer_classАтрибуты. Например:

class AccountViewSet(viewsets.ModelViewSet):
    """
    用于查看和编辑 Account
    """
    queryset = Account.objects.all()
    serializer_class = AccountSerializer
    permission_classes = [IsAccountAdminOrReadOnly]

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

class AccountViewSet(viewsets.ModelViewSet):
    """
    A simple ViewSet for viewing and editing the accounts
    associated with the user.
    """
    serializer_class = AccountSerializer
    permission_classes = [IsAccountAdminOrReadOnly]

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

Но учтите, что изViewSetУдалитьquerysetсвойство, любые связанные маршрутизаторы не смогут автоматически экспортировать модельbase_name, поэтому вы должны положитьbase_nameKwarg указывается как часть регистрации маршрутизатора.

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

ReadOnlyModelViewSet

ReadOnlyModelViewSetкласс тоже изGenericAPIViewнаследовать. иModelViewSetМол, он тоже содержит реализацию различных операций, но сModelViewSetРазница в том, что он обеспечивает только операции «только для чтения»,.list()и.retrieve().

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

иModelViewSetНапример, вам обычно нужно предоставить как минимумquerysetиserializer_classАтрибуты. Например:

class AccountViewSet(viewsets.ReadOnlyModelViewSet):
    """
    A simple ViewSet for viewing accounts.
    """
    queryset = Account.objects.all()
    serializer_class = AccountSerializer

Точно так же сModelViewSetНапример, вы можете переопределитьGenericAPIViewДоступны любые стандартные свойства и методы.

Набор базовых классов на заказ

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

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

Чтобы создать предложениеcreate,listиretrieveБазовый класс набора представлений для операций, начиная сGenericViewSetНаследовать и смешать нужные операции:

from rest_framework import mixins

class CreateListRetrieveViewSet(mixins.CreateModelMixin,
                                mixins.ListModelMixin,
                                mixins.RetrieveModelMixin,
                                viewsets.GenericViewSet):
    """
    A viewset that provides `retrieve`, `create`, and `list` actions.

    To use it, override the class and set the `.queryset` and
    `.serializer_class` attributes.
    """
    pass

Создав собственную базовуюViewSetКлассы, которые обеспечивают общее поведение, которое можно повторно использовать в нескольких наборах представлений в API.