Django REST framework允许将一组视图的逻辑组合在一个单独的类中,成为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 rest_framework import viewsets
from rest_framework.response import Response
from myapps.serializers import UserSerializer


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 rest_framework.routers import DefaultRouter
from myapp.views import UserViewSet


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类有两个优点:

  • 重复的逻辑可以组合成一个类。在上面的示例中,只需要指定一次queryset,它将在多个视图中使用。
  • 通过使用routers,不再需要处理自己的URL连接。

视图集操作

REST framework中包含的默认路由器将为一套标准的创建/检索/更新/销毁样式操作提供路由。

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

反思视图集操作

在调度旗舰,ViewSet上提供了一下属性。

  • basename:用于创建的URL名称的基础。
  • action:当前操作的名称。
  • detail:布尔值,指示是否为列表或详细信息视图配置了当前操作。
  • suffix:视图集类型的显示后缀,detail属性的镜像。
  • name:视图集的显示名称,与suffix互斥。
  • description:视图集的单个视图的显示说明。
def get_permissions(self):
    """
    实现并返回该视图所需的权限列表
    """
    if self.action == "list":
        permission_classes = [IsAuthenticated]
    else:
        permission_classes = [IsAdmin]
    return [permission() for permission in permission_classes]

标记路由的额外操作

如果有可路由的特殊方法,可以使用@action装饰器来标记它们。与常规操作一样,额外的操作可以用于对象列表或者单个实例。要指出这一点,设置detail参数为True或False。路由器将相应地配置其URL模式。例如,DefaultRouter将在其URLconf中配置包含pk的详细操作。

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

class UserViewSet(viewsets.ModelViewSet):
    queryset = User.objects.all()
    serializer_class = UserSerializer

    @action(detail=True, 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)

    @action(detail=False)
    def recent_users(self, request):
        recent_users = User.objects.all().order_by('-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)

装饰器还可以采用仅为路由视图设置的额外参数。

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

该action装饰器将路由GET默认请求,但也可以通过设置接收其他HTTP方法methods的参数。

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

然后,两个新的动作将在^users/{pk}/set_password/$^users/{pk}/unset_password/$

为额外操作路由其他HTTP方法

额外的操作可以将其他HTTP方法映射到单独的ViewSet方法。例如,上述密码设置/未设置方法可以合并为单个路由。请注意,其他映射不接受参数。

@action(detail=True, methods=['put'], name='Change Password')
def password(self, request, pk=None):
    ...

@password.mapping.delete
def delete_password(self, request, pk=None):
    ...

反向操作urls

如果需要获取操作的URL,请使用.reverse_action()方法。这是Reverse()的遍历封装,它将自动传递视图的request对象,并在url_name前加上.basename属性。
注意,basename是路由器在ViewSet注册旗舰提供的。如果不适用路由器,则必须向.as_view()方法提供basename参数。

API参考

ViewSet

ViewSet类继承自APIView。可以是使用任何标准属性来控制视图集上的API策略。
ViewSet类不提供任何操作的实现。为了使用ViewSet类,将重写该类并显式地定义操作的实现。

GenericViewSet

GenericViewSet类继承自GenericAPIView,并提供默认的get_object,get_queryset方法和其他通用视图基本行为,但默认情况下不包含任何操作。
为了使用GenericViewSet类,你将重写该类,或混合所需的mixin类,或者显式定义操作实现。

ModelViewSet

ModelViewSet类继承自GenericAPIView,并通过混合各种mixin类的行为来包含各种操作的实现。
ModelViewSet类提供的操作有.list(), .retrieve(), .create(), .update(), .partial_update().destroy()
示例:
因为ModelViewSet扩展了GenericAPIView,所以通常需要至少提供queryset和serializer_class属性。

class AccountViewSet(viewsets.ModelViewSet):
    """
    查看和编辑账户的视图集
    """
    queryset = Account.objects.all()
    serializer_class = AccountSerializer
    permission_classes = [IsAccountAdminOrReadOnly]

可以使用GenericAPIView提供的任何标准属性或方法重写。

class AccountViewSet(views.ModelViewSet):
    serializer_class = AccountSerializer
    permission_classes = [IsAccountAdminOrReadOnly]

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

注意,当从ViewSet中移除queryset属性,任何关联的路由器将无法自动导出模型的base_name,因此必须制定base_nane kwarg作为路由器注册的一部分。
还要注意,尽管这个类默认情况下提供了完整创建/列表/检索/更新/销毁操作集,但是可以使用标准权限来限制可用操作。

ReadOnlyModelViewSet

ReadOnlyModelViewSet类继承自GenericAPIView。与ModelViewSet一样,它还包括各种操作的实现,但与ModelViewSet不同,它只提供只读操作,.list().retrieve()
示例:
与ModelViewSet一样,通常需要至少提供queryset和serializer_class属性。

class AccountViewSet(viewsets.ReadOnlyModelViewSet):
    queryset = Account.objects.all()
    serializer_class = AccountSerializer

同样,与ModelViewSet一样,可以使用GenericAPIView可用的任何标准属性和方法发重写。

自定义视图集基类

有时候可能需要提供自定义ViewSet类,这些类没有完整的ModelViewSet操作集,或者以其他方式自定义行为。
实例:
创建提供create, list和retrieve操作的基本视图集类,需继承GenericViewSet,并混合所需的操作:

from rest_framework import mixins


class CreateListRetrieveViewSet(mixins.CreateModelMixin,
                                mixins.ListModelMixin,
                                mixins.RetrieveModelMixin,
                                viewsets.GenericViewSet):
    pass

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

0条评论

相关推荐

django教程

r

Django 2019-05-20 10:53:53

Celery

celery学习资料

Django 2019-05-25 18:41:55

django教程入门

适合django新人使用的学习手册

Django 2019-07-01 14:28:04

django实用资料

django项目从0到1自己总结的实用的资料,大部分常用的功能这里都有

Django 2019-05-08 18:21:34