视图集合

路由确定哪个控制器用于请求后,您的控制器负责了解请求并产生适当的输出。
…..Ruby on Rails文档

Django REST框架允许您将一组相关视图的逻辑组合在一个类中,称为 ViewSet。在其他框架中,您也可以在概念上找到名为“资源”或“控制器”的类似实现。

ViewSet类只是一种类型的基于类的视图,即不提供任何方法的处理程序,例如,而是提供.get()或.post()操作,代替如.list()和.create()。

使用.as_view()该方法,处理程序ViewSet仅限于完成视图时的相应操作。

通常,而不是在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):
    """
    A simple ViewSet for listing or retrieving users.
    """
    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):
    """
    A viewset for viewing and editing user instances.
    """
    serializer_class = UserSerializer
    queryset = User.objects.all()

使用ViewSet类比使用View类有两个主要优点。

  • 重复的逻辑可以组合成一个类。在上面的例子中,我们只需要指定queryset一次,就可以在多个视图中使用。
  • 通过使用路由器,我们不再需要处理配置自己的URL。
    权衡利弊。使用常规视图和URL confs更加明确,并为您提供更多的控制。如果您想要快速启动并运行View API,或者当您有一个较大的API,并且您想要一致地执行一致的URL配置时,ViewSets将非常有用。

为路由标记临时的操作

REST框架中包含的默认路由器将为标准的create / retrieve / update / destroy样式操作,如下所示:

class UserViewSet(viewsets.ViewSet):
    """
    Example empty viewset demonstrating the standard
    actions that will be handled by a router class.

    If you're using format suffixes, make sure to also include
    the `format=None` keyword argument for each action.
    """

    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

如果您需要路由到特殊方法,则可以将其标记为需要使用@detail_route或@list_route修饰符的路由。

该@detail_route装饰包含pk在URL模式,旨在为需要的单个实例方法。该@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):
    """
    A viewset that provides the standard actions
    """
    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):
       ...

然后,这两个新的动作可以在网址^users/{pk}/set_password/和users/pk/unsetpassword/
获得

API参考

视图集合

将ViewSet类继承APIView。您可以使用任何标准属性,例如permission_classes,authentication_classes以便在视图集上控制API策略。

本ViewSet类不提供任何操作实现。为了使用ViewSet类,您将覆盖类并明确定义操作实现。

类的视图集合

GenericViewSet继承GenericAPIView,并提供了默认设置get_object,get_queryset方法及其他通用视图基于的行为,但不包括默认情况下,任何动作。

为了使用GenericViewSet类,您将覆盖该类,并混合所需的mixin类,或明确定义操作实现。

模型的视图集合

ModelViewSet类继承GenericAPIView,并包括用于各种方法实现方式,通过在各种混入类的行为混合。

由ModelViewSet类提供的动作是.list(),.retrieve(), .create(),.update(),.partial_update(),和.destroy()。

例如

因为ModelViewSet扩展GenericAPIView,通常需要至少提供queryset和serializer_class属性。例如:

class AccountViewSet(viewsets.ModelViewSet):
    """
    A simple ViewSet for viewing and editing accounts.
    """
    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()

请注意,queryset属性从您的ViewSet中删除后,任何关联的路由器将无法自动导出模型的base_name,因此您必须指定base_namekwarg作为路由器注册的一部分。

另请注意,虽然此类默认情况下提供了完整的create / list / retrieve / update / destroy操作,但您可以使用标准权限类来限制可用的操作。

只读模型视图集合

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的多个视图中重用的常见行为。