• rest framework ViewSet


    ViewSets

    路由选择确定要用于一个请求哪个控制器之后,控制器负责做出请求的感并产生相应的输出。

    - Ruby on Rails的文档

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

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

    用于该方法的处理程序ViewSet,在最终确定视图中,使用的点仅绑定到相应的动作.as_view()方法。

    通常情况下,而不是明确地注册在URL配置一个视图集的意见,你会注册一个路由器类的视图集,可以自动确定您URL配置。

    让我们来定义一个简单的视图集,可用于列表或检索系统中的所有用户。

    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'})
    

    通常,我们不会这么做,而是会注册一个路由器的视图集,并允许自动生成的URL配置。

    from myapp.views import UserViewSet
    from rest_framework.routers import DefaultRouter
    
    router = DefaultRouter()
    router.register(r'users', UserViewSet, basename='user')
    urlpatterns = router.urls
    

    而不是写你自己的viewsets,你会经常要使用现有的基础类,它们提供行为的默认设置。例如:

    class UserViewSet(viewsets.ModelViewSet):
        """
        A viewset for viewing and editing user instances.
        """
        serializer_class = UserSerializer
        queryset = User.objects.all()
    

    有使用的两个主要优点ViewSet类使用上一个View类。

    • 重复逻辑可以组合成一个单一的类。在上面的例子中,我们只需要指定queryset一次,它会在多个视图中使用。
    • 通过使用路由器,我们不再需要处理类设置URL的conf自己。

    这两个配备了权衡。使用常规视图和URL confs是更加明确,为您提供更多的控制。ViewSets是有益的,如果你想获得迅速启动和运行,或当你有一个大的API,并要强制贯穿一致的URL配置。

    视图集中行动

    包含REST框架默认的路由器将提供一组标准的创建/检索/更新/销毁风格的动作,途径如下图所示:

    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
    

    内省视图集中行动

    在放行时,下列属性可用的ViewSet

    • basename - 基本用于所创建的URL名称。
    • action-当前操作的名称(例如listcreate)。
    • detail - 布尔值,指示如果当前的动作被配置为列表或详细视图。
    • suffix-反射镜的-为对视图集型的显示后缀detail属性。
    • name-为视图集的显示名称。这种说法是互斥的suffix
    • description - 用于视图集的各个视图中的显示的说明。

    您可以检查这些属性根据当前的动作来调整行为。例如,你可以限制权限,除了一切list与此类似的行动:

    def get_permissions(self):
        """
        Instantiates and returns the list of permissions that this view requires.
        """
        if self.action == 'list':
            permission_classes = [IsAuthenticated]
        else:
            permission_classes = [IsAdmin]
        return [permission() for permission in permission_classes]
    

    标记路由额外行动

    如果你有特别的方法应该是可路由的,你可以将它们标记为这样的与@action装饰。像普通的行动,额外的操作会被用于任何单个对象或整个集合。为了说明这一点,设置detail参数TrueFalse。路由器将相应地配置其URL模式。例如,DefaultRouter将配置详细的行动包含pk在他们的URL模式。

    额外行动的更完整的例子:

    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):
        """
        A viewset that provides the standard actions
        """
        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/$

    要查看所有多余的动作,调用.get_extra_actions()方法。

    路由额外行动额外的HTTP方法

    额外的动作可以映射其他HTTP方法分离ViewSet的方法。例如,上述的密码设置/取消方法可以合并成一个单一的路由。需要注意的是附加映射不接受参数。

        @action(detail=True, methods=['put'], name='Change Password')
        def password(self, request, pk=None):
            """Update the user's password."""
            ...
    
        @password.mapping.delete
        def delete_password(self, request, pk=None):
            """Delete the user's password."""
            ...
    
    

    扭转操作URL

    如果你需要得到一个动作的URL,使用.reverse_action()方法。这是一个方便的包装reverse(),自动传递视图的request对象和前面加上url_name.basename属性。

    请注意,basename是由路由器期间提供ViewSet登记。如果您没有使用路由器,则必须提供basename参数的.as_view()方法。

    使用前面部分的示例:

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

    另外,您也可以使用url_name由设置属性@action装饰。

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

    url_name论据.reverse_action()应该与相同参数的@action装饰。此外,该方法可用于扭转默认动作,如listcreate


    API参考

    视图集

    ViewSet类从继承APIView。您可以使用任何标准的属性,如permission_classesauthentication_classes以控制在视图集的API政策。

    ViewSet类不提供任何操作实现。为了使用一个ViewSet类,你会覆盖类,并明确定义的操作实现。

    GenericViewSet

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

    为了使用一个GenericViewSet类,你会覆盖类,要么混入所需的混入类,或者明确定义的操作实现。

    ModelViewSet

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

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

    因为ModelViewSet延伸GenericAPIView,你通常需要提供至少querysetserializer_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,任何相关的路由器将无法自动推导模型的基本名称,所以你必须指定basenamekwarg作为您的一部分路由器注册

    还要注意的是,虽然这个类提供了一套完整的创建/列表/检索/更新/销毁默认操作,您可以使用标准的权限类限制可用的操作。

    ReadOnlyModelViewSet

    ReadOnlyModelViewSet班也继承GenericAPIView。正如ModelViewSet它也包括了各种动作的实现,但不像ModelViewSet只提供“只读”的行动,.list().retrieve()

    正如ModelViewSet,你通常需要提供至少querysetserializer_class属性。例如:

    class AccountViewSet(viewsets.ReadOnlyModelViewSet):
        """
        A simple ViewSet for viewing accounts.
        """
        queryset = Account.objects.all()
        serializer_class = AccountSerializer
    

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

    自定义视图集中的基类

    您可能需要提供自定义ViewSet不具有完整的一组类ModelViewSet的行动,或者定制一些其他方式的行为。

    要创建基础视图集类,提供createlistretrieve操作,继承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多个viewsets重复使用共同的行为。

  • 相关阅读:
    求最大子数组和
    第四周学习进度
    四则运算3
    实用工具箱app开发日记5
    实用工具箱app开发日记4
    实用工具箱app开发日记3
    实用工具箱app开发日记2
    实用工具箱app开发日记1
    《软件需求与分析》阅读笔记
    软件需求分析--阅读笔记3
  • 原文地址:https://www.cnblogs.com/pyliuwei/p/12468705.html
Copyright © 2020-2023  润新知