zoukankan      html  css  js  c++  java
  • 视图家族之视图工具集viewsets

    视图家族之视图工具集viewsets

    一、视图集ViewSet

    使用视图集ViewSet,可以将一系列逻辑相关的动作放到一个类中:

    • list() 提供一组数据
    • retrieve() 提供单个数据
    • create() 创建数据
    • update() 保存数据
    • destory() 删除数据

    ViewSet视图集类不再实现get()、post()等方法,而是通过重写as_view函数进行映射实现动作 action 如 list() 、create() 等。

    视图集只在使用as_view()方法的时候,才会将action动作与具体请求方式对应上。如:

    # 视图工具集
    from rest_framework import viewsets
    class BookInfoViewSet(viewsets.ViewSet):
    
        def list(self, request):
            books = BookInfo.objects.all()
            serializer = BookInfoSerializer(books, many=True)
            return Response(serializer.data)
    
        def retrieve(self, request, pk=None):
            try:
                books = BookInfo.objects.get(id=pk)
            except BookInfo.DoesNotExist:
                return Response(status=status.HTTP_404_NOT_FOUND)
            serializer = BookInfoSerializer(books)
            return Response(serializer.data)
    

    在设置路由时,我们可以如下操作

    urlpatterns = [
        url(r'^books/$', BookInfoViewSet.as_view({'get':'list'}),
        url(r'^books/(?P<pk>d+)/$', BookInfoViewSet.as_view({'get': 'retrieve'})
    ]
    

    常用视图集父类

    1) ViewSet

    继承自APIViewViewSetMixin,作用也与APIView基本类似,提供了身份认证、权限校验、流量管理等。

    ViewSet主要通过继承ViewSetMixin来实现在调用as_view()时传入字典(如{'get':'list'})的映射处理工作。

    在ViewSet中,没有提供任何动作action方法,需要我们自己实现action方法。

    2)GenericViewSet

    使用ViewSet通常并不方便,因为list、retrieve、create、update、destory等方法都需要自己编写,而这些方法与前面讲过的Mixin扩展类提供的方法同名,所以我们可以通过继承Mixin扩展类来复用这些方法而无需自己编写。但是Mixin扩展类依赖与GenericAPIView,所以还需要继承GenericAPIView

    GenericViewSet就帮助我们完成了这样的继承工作,继承自GenericAPIViewViewSetMixin,在实现了调用as_view()时传入字典(如{'get':'list'})的映射处理工作的同时,还提供了GenericAPIView提供的基础方法,可以直接搭配Mixin扩展类使用。

    举例:

    from rest_framework import mixins
    from rest_framework.viewsets import GenericViewSet
    from rest_framework.decorators import action
    
    class BookInfoViewSet(mixins.ListModelMixin, mixins.RetrieveModelMixin, GenericViewSet):
        queryset = BookInfo.objects.all()
        serializer_class = BookInfoSerializer
    

    url的定义

    urlpatterns = [
        url(r'^books/$', views.BookInfoViewSet.as_view({'get': 'list'})),
        url(r'^books/(?P<pk>d+)/$', views.BookInfoViewSet.as_view({'get': 'retrieve'})),
    ]
    

    3)ModelViewSet

    继承自GenericViewSet,同时包括了ListModelMixin、RetrieveModelMixin、CreateModelMixin、UpdateModelMixin、DestoryModelMixin。

    4)ReadOnlyModelViewSet

    继承自GenericViewSet,同时包括了ListModelMixin、RetrieveModelMixin。

    视图集中定义附加action动作

    在视图集中,除了上述默认的方法动作外,还可以添加自定义动作。

    举例:

    from rest_framework import mixins
    from rest_framework.viewsets import GenericViewSet
    from rest_framework.decorators import action
    
    class BookInfoViewSet(mixins.ListModelMixin, mixins.RetrieveModelMixin, GenericViewSet):
        queryset = BookInfo.objects.all()
        serializer_class = BookInfoSerializer
    
        def latest(self, request):
            """
            返回最新的图书信息
            """
            book = BookInfo.objects.latest('id')
            serializer = self.get_serializer(book)
            return Response(serializer.data)
    
        def read(self, request, pk):
            """
            修改图书的阅读量数据
            """
            book = self.get_object()
            book.bread = request.data.get('read')
            book.save()
            serializer = self.get_serializer(book)
            return Response(serializer.data)
    

    url的定义

    urlpatterns = [
        url(r'^books/$', views.BookInfoViewSet.as_view({'get': 'list'})),
        url(r'^books/latest/$', views.BookInfoViewSet.as_view({'get': 'latest'})),
        url(r'^books/(?P<pk>d+)/$', views.BookInfoViewSet.as_view({'get': 'retrieve'})),
        url(r'^books/(?P<pk>d+)/read/$', views.BookInfoViewSet.as_view({'put': 'read'})),
    ]
    

    action属性

    在视图集中,我们可以通过action对象属性来获取当前请求视图集时的action动作是哪个。

    例如:

    from rest_framework.viewsets import ModelViewSet,ReadOnlyModelViewSet
    from booktest.models import BookInfo
    from .serializers import BookInfoModelSerializer
    from rest_framework.response import Response
    class BookInfoModelViewSet(ModelViewSet):
        queryset = BookInfo.objects.all()
        serializer_class = BookInfoModelSerializer
    
        def get_top_5(self,request):
            """获取评论值最多的5条数据"""
            # 操作数据库
            print(self.action) # 获取本次请求的视图方法名
            
            
    通过路由访问到当前方法中.可以看到本次的action就是请求的方法名
    

    二、总结

    1. 重写as_views()方法通过反射机制实现对应功能的请求,as_views()完成了请求自定义映射,将所有请求方式与响应方法名,通过映射关系交给用户自己配置
    2. GenericViewSet类作为ReadOnlyModelViewSet的父类类作为ReadOnlyModelViewSet的父类,解决了单查和群查共存,实现继承工具类中的单查和群查的方法
    3. ViewSet和GenericViewSet类的区别:登录接口post不需要增
    4. 所以GenericViewSet标准的资源接口post请求一定会往数据库中增,ViewSet他是非资源接口post不需要数据库增数据的交互
    5. 可以实现自定义请求的方法
        def as_view(cls, actions=None, **initkwargs):
            """
            Because of the way class based views create a closure around the
            instantiated view, we need to totally reimplement `.as_view`,
            and slightly modify the view function that is created and returned.
            """
            # The name and description initkwargs may be explicitly overridden for
            # certain route configurations. eg, names of extra actions.
            cls.name = None
            cls.description = None
    
            # The suffix initkwarg is reserved for displaying the viewset type.
            # This initkwarg should have no effect if the name is provided.
            # eg. 'List' or 'Instance'.
            cls.suffix = None
    
            # The detail initkwarg is reserved for introspecting the viewset type.
            cls.detail = None
    
            # Setting a basename allows a view to reverse its action urls. This
            # value is provided by the router through the initkwargs.
            cls.basename = None
    
            # actions must not be empty
            if not actions:
                raise TypeError("The `actions` argument must be provided when "
                                "calling `.as_view()` on a ViewSet. For example "
                                "`.as_view({'get': 'list'})`")
    
            # sanitize keyword arguments
            for key in initkwargs:
                if key in cls.http_method_names:
                    raise TypeError("You tried to pass in the %s method name as a "
                                    "keyword argument to %s(). Don't do that."
                                    % (key, cls.__name__))
                if not hasattr(cls, key):
                    raise TypeError("%s() received an invalid keyword %r" % (
                        cls.__name__, key))
    
            # name and suffix are mutually exclusive
            if 'name' in initkwargs and 'suffix' in initkwargs:
                raise TypeError("%s() received both `name` and `suffix`, which are "
                                "mutually exclusive arguments." % (cls.__name__))
    
            def view(request, *args, **kwargs):
                self = cls(**initkwargs)
                # We also store the mapping of request methods to actions,
                # so that we can later set the action attribute.
                # eg. `self.action = 'list'` on an incoming GET request.
                self.action_map = actions
    			
                # 设置具体执行函数响应
                for method, action in actions.items():
                    handler = getattr(self, action)
                    setattr(self, method, handler)
    
                if hasattr(self, 'get') and not hasattr(self, 'head'):
                    self.head = self.get
    
                self.request = request
                self.args = args
                self.kwargs = kwargs
    
                # And continue as usual
                return self.dispatch(request, *args, **kwargs)
    
            # take name and docstring from class
            update_wrapper(view, cls, updated=())
    
            update_wrapper(view, cls.dispatch, assigned=())
    
            view.cls = cls
            view.initkwargs = initkwargs
            view.actions = actions
            return csrf_exempt(view)
    
  • 相关阅读:
    井字棋先手必胜图解
    python 回溯法 子集树模板 系列 —— 19、野人与传教士问题
    pandas 索引与列相互转化
    按概率随机选取
    java中文乱码解决之道(二)-----字符编码详解:基础知识 + ASCII + GB**
    java中文乱码解决之道(一)-----认识字符集
    Java提高篇(三八)-----Java集合细节(四):保持compareTo和equals同步
    Java提高配(三七)-----Java集合细节(三):subList的缺陷
    Java提高篇(三六)-----Java集合细节(二):asList的缺陷
    Java提高篇(三五)-----Java集合细节(一):请为集合指定初始容量
  • 原文地址:https://www.cnblogs.com/randysun/p/12292731.html
Copyright © 2011-2022 走看看