Django drf ViewSets
ViewSets
在路由已经确定了用于请求的控制器之后,你的控制器负责理解请求并产生适当的输出。— Ruby on Rails 文档
Django REST framework允许你将一组相关视图的逻辑组合在单个类(称为 ViewSet)中。 在其他框架中,你也可以找到概念上类似于 'Resources' 或 'Controllers'的类似实现。
ViewSet 只是一种基于类的视图,它不提供任何方法处理程序(如 .get()或.post()),而是提供诸如 .list() 和 .create() 之类的操作。
ViewSet 的方法处理程序仅使用 .as_view() 方法绑定到完成视图的相应操作。
通常不是在 urlconf 中的视图集中显示注册视图,而是要使用路由类注册视图集,该类会自动为你确定 urlconf。
Example
让我们定义一个简单的视图集,可以用来列出或检索系统中的所有用户。
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)
如果我们需要,我们可以将这个viewset绑定到两个单独的视图,想这样:
user_list = UserViewSet.as_view({'get': 'list'})
user_detail = UserViewSet.as_view({'get': 'retrieve'})
通常我们不会这么做,我们会用一个router来注册我们的viewset,让urlconf自动生成。
from myapp.views import UserViewSet
from rest_framework.routers import DefaultRouter
router = DefaultRouter()
router.register(r'users', UserViewSet)
urlpatterns = router.urls
不需要编写自己的视图集,你通常会想要使用提供默认行为的现有基类。例如:
class UserViewSet(viewsets.ModelViewSet):
"""
用于查看和编辑用户实例的视图集。
"""
serializer_class = UserSerializer
queryset = User.objects.all()
与使用 View 类相比,使用 ViewSet 类有两个主要优点。
- 重复的逻辑可以组合成一个类。在上面的例子中,我们只需要指定一次 queryset,它将在多个视图中使用。
- 通过使用 routers, 哦们不再需要自己处理URLconf。
这两者都有一个权衡。使用常规的 views 和 URL confs 更明确也能够为你提供更多的控制。ViewSets有助于快速启动和运行,或者当你有大型的API,并且希望在整个过程中执行一致的 URL 配置。
标记路由的额外操作
REST framework 中包含的默任 routes 将为标准的 create/retrieve/update/destroy 类型操作提供路由, 如下所示:
class UserViewSet(viewsets.ViewSet):
"""
示例 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
如果你有需要被路由到的特别方法,你可以使用 @detail_route 或 @list_route 装饰器将它们标记为需要路由。
@detail_route 装饰器在其URL模式中包含 pk 用于需要单个实例的方法。The @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):
"""
一个提供标准动作的 viewset
"""
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):
...
这两个新动作将在 urls ^users/{pk}/set_password/$ 和 ^users/{pk}/unset_password/$上可用。
更多建议: