视图集合
路由确定哪个控制器用于请求后,您的控制器负责了解请求并产生适当的输出。
…..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的多个视图中重用的常见行为。