• 视图集
    • 举个栗子
    • 操作视图集
    • 标记额外的路由行为
    • action 跳转
  • API 参考
    • ViewSet
    • GenericViewSet
    • ModelViewSet
    • ReadOnlyModelViewSet
  • 自定义视图集基类

    官方原文链接

    视图集

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

    Django REST framework 允许将一组相关视图的逻辑组合到一个称为 ViewSet 的类中。在其他框架中,您可能会发现概念上类似的实现,名为 “Resources” 或 “Controllers” 。

    ViewSet 类只是一种基于类的 View,它不提供任何处理方法,如 .get().post(),而是提供诸如 .list().create() 之类的操作。

    ViewSet 只在用 .as_view() 方法绑定到最终化视图时做一些相应操作。

    通常,不是在 urlconf 中的视图集中明确注册视图,而是使用路由器类注册视图集,这会自动为您确定 urlconf。

    举个栗子

    定义一个简单的视图集,可以用来列出或检索系统中的所有用户。

    1. from django.contrib.auth.models import User
    2. from django.shortcuts import get_object_or_404
    3. from myapps.serializers import UserSerializer
    4. from rest_framework import viewsets
    5. from rest_framework.response import Response
    6. class UserViewSet(viewsets.ViewSet):
    7. def list(self, request):
    8. queryset = User.objects.all()
    9. serializer = UserSerializer(queryset, many=True)
    10. return Response(serializer.data)
    11. def retrieve(self, request, pk=None):
    12. queryset = User.objects.all()
    13. user = get_object_or_404(queryset, pk=pk)
    14. serializer = UserSerializer(user)
    15. return Response(serializer.data)

    如果需要,可以将这个视图集合成两个单独的视图,如下所示:

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

    通常情况下,我们不会这样做,而是用路由器注册视图集,并允许自动生成 urlconf。

    1. from myapp.views import UserViewSet
    2. from rest_framework.routers import DefaultRouter
    3. router = DefaultRouter()
    4. router.register(r'users', UserViewSet, base_name='user')
    5. urlpatterns = router.urls

    不用自己编写视图集,通常使用默认提供的现有基类。例如:

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

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

    • 重复的逻辑可以合并成一个类。在上面的例子中,我们只需要指定一次查询集,它将在多个视图中使用。
    • 通过使用 routers,我们不再需要处理自己的 URL 配置。

    这两者各有优缺点。使用常规视图和 URL 配置文件更加明确,并为您提供更多控制。如果想要更快速的开发出一个应用,或者需要使大型 API 的 URL 配置始终保持一致,视图集会非常有用。

    操作视图集

    REST framework 中包含的默认 routes 将为一组标准的 create / retrieve / update / destroy 风格 action 提供路由,如下所示:

    1. class UserViewSet(viewsets.ViewSet):
    2. """
    3. 这些方法将由路由器负责处理。
    4. 如果要使用后缀,请确保加上 `format = None` 关键字参数
    5. """
    6. def list(self, request):
    7. pass
    8. def create(self, request):
    9. pass
    10. def retrieve(self, request, pk=None):
    11. pass
    12. def update(self, request, pk=None):
    13. pass
    14. def partial_update(self, request, pk=None):
    15. pass
    16. def destroy(self, request, pk=None):
    17. pass

    在调度期间,当前 action 的名称可以通过 .action 属性获得。您可以检查 .action 以根据当前 action 调整行为。

    例如,您可以将权限限制为只有 admin 才能访问 list 以外的其他 action,如下所示:

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

    标记额外的路由行为

    如果需要路由特定方法,则可以用 @detail_route@list_route 装饰器进行修饰。

    @detail_route 装饰器在其 URL 模式中包含 pk,用于支持需要获取单个实例的方法。@list_route 修饰器适用于在对象列表上操作的方法。

    举个栗子:

    1. from django.contrib.auth.models import User
    2. from rest_framework import status
    3. from rest_framework import viewsets
    4. from rest_framework.decorators import detail_route, list_route
    5. from rest_framework.response import Response
    6. from myapp.serializers import UserSerializer, PasswordSerializer
    7. class UserViewSet(viewsets.ModelViewSet):
    8. """
    9. 提供标准操作的视图集
    10. """
    11. queryset = User.objects.all()
    12. serializer_class = UserSerializer
    13. @detail_route(methods=['post'])
    14. def set_password(self, request, pk=None):
    15. user = self.get_object()
    16. serializer = PasswordSerializer(data=request.data)
    17. if serializer.is_valid():
    18. user.set_password(serializer.data['password'])
    19. user.save()
    20. return Response({'status': 'password set'})
    21. else:
    22. return Response(serializer.errors,
    23. status=status.HTTP_400_BAD_REQUEST)
    24. @list_route()
    25. def recent_users(self, request):
    26. recent_users = User.objects.all().order('-last_login')
    27. page = self.paginate_queryset(recent_users)
    28. if page is not None:
    29. serializer = self.get_serializer(page, many=True)
    30. return self.get_paginated_response(serializer.data)
    31. serializer = self.get_serializer(recent_users, many=True)
    32. return Response(serializer.data)

    另外,装饰器可以为路由视图设置额外的参数。例如…

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

    这些装饰器默认路由 GET 请求,但也可以使用 methods 参数接受其他 HTTP 方法。例如:

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

    这两个新操作将在 urls ^users/{pk}/set_password/$^users/{pk}/unset_password/$ 上。

    action 跳转

    如果你需要获取 action 的 URL ,请使用 .reverse_action() 方法。这是 .reverse() 的一个便捷包装,它会自动传递视图的请求对象,并将 url_name.basename 属性挂接。

    请注意,basename 是在 ViewSet 注册过程中由路由器提供的。如果您不使用路由器,则必须提供.as_view() 方法的 basename 参数。

    使用上一节中的示例:

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

    url_name 参数应该与 @list_route@detail_route 装饰器的相同参数匹配。另外,这可以用来反转默认 listdetail 路由。

    API 参考

    ViewSet

    ViewSet 类继承自 APIView。您可以使用任何标准属性(如 permission_classesauthentication_classes)来控制视图上的 API 策略。

    ViewSet 类不提供任何 action 的实现。为了使用 ViewSet 类,必须继承该类并明确定义 action 实现。

    GenericViewSet

    GenericViewSet 类继承自 GenericAPIView,并提供默认的 get_objectget_queryset 方法和其他通用视图基础行为,但默认情况下不包含任何操作。

    为了使用 GenericViewSet 类,必须继承该类并混合所需的 mixin 类,或明确定义操作实现。

    ModelViewSet

    ModelViewSet 类继承自 GenericAPIView,并通过混合各种 mixin 类的行为来包含各种操作的实现。

    ModelViewSet 提供的操作有 .list() , .retrieve() , .create() , .update() , .partial_update(), 和 .destroy()

    举个栗子:

    由于 ModelViewSet 类继承自 GenericAPIView,因此通常需要提供至少 querysetserializer_class 属性。例如:

    1. class AccountViewSet(viewsets.ModelViewSet):
    2. """
    3. 用于查看和编辑 Account
    4. """
    5. queryset = Account.objects.all()
    6. serializer_class = AccountSerializer
    7. permission_classes = [IsAccountAdminOrReadOnly]

    请注意,您可以覆盖 GenericAPIView 提供的任何标准属性或方法。例如,要动态确定它应该操作的查询集的ViewSet,可以这样做:

    1. class AccountViewSet(viewsets.ModelViewSet):
    2. """
    3. A simple ViewSet for viewing and editing the accounts
    4. associated with the user.
    5. """
    6. serializer_class = AccountSerializer
    7. permission_classes = [IsAccountAdminOrReadOnly]
    8. def get_queryset(self):
    9. return self.request.user.accounts.all()

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

    还要注意,虽然这个类默认提供了完整的 create / list / retrieve / update / destroy 操作集,但您可以通过使用标准权限类来限制可用操作。

    ReadOnlyModelViewSet

    ReadOnlyModelViewSet 类也从 GenericAPIView 继承。与 ModelViewSet 一样,它也包含各种操作的实现,但与 ModelViewSet 不同的是它只提供 “只读” 操作,.list().retrieve()

    举个栗子:

    ModelViewSet 一样,您通常需要提供至少 querysetserializer_class 属性。例如:

    1. class AccountViewSet(viewsets.ReadOnlyModelViewSet):
    2. """
    3. A simple ViewSet for viewing accounts.
    4. """
    5. queryset = Account.objects.all()
    6. serializer_class = AccountSerializer

    同样,与 ModelViewSet 一样,您可以覆盖GenericAPIView 可用的任何标准属性和方法。

    自定义视图集基类

    您可能需要使用没有完整 ModelViewSet 操作集的自定义 ViewSet 类,或其他自定义行为。

    举个栗子:

    要创建提供 createlistretrieve 操作的基本视图集类,请从 GenericViewSet 继承,并混合(mixin )所需的操作:

    1. from rest_framework import mixins
    2. class CreateListRetrieveViewSet(mixins.CreateModelMixin,
    3. mixins.ListModelMixin,
    4. mixins.RetrieveModelMixin,
    5. viewsets.GenericViewSet):
    6. """
    7. A viewset that provides `retrieve`, `create`, and `list` actions.
    8. To use it, override the class and set the `.queryset` and
    9. `.serializer_class` attributes.
    10. """
    11. pass

    通过创建自己的基本 ViewSet 类,能够提供可在 API 中的多个视图集中重用的常见行为。