zoukankan      html  css  js  c++  java
  • Django(58)viewsets视图集详解

    前言

    ViewSet 只是一种基于类的视图,它不提供任何方法处理程序(如 .get().post()),而是提供诸如.list().create() 之类的操作。
    ViewSet 的方法处理程序仅使用 .as_view() 方法绑定到完成视图的相应操作。
    通常不是在urlconf中的视图集中显示注册视图,而是要使用路由类注册视图集,该类会自动为你确定 urlconf
     

    源码分析

    我们首先看一下viewsets.py文件的源码结构,如下图

    我们可以看到有5个类

    • ViewSetMixin
    • ViewSet:继承自ViewSetMixinAPIView
    • GenericViewSet:继承自ViewSetMixinGenericAPIView
    • ReadOnlyModelViewSet:继承自RetrieveModelMixinListModelMixinGenericViewSet
    • ModelViewSet:继承自5大mixins工具类和GenericViewSet
       

    ViewSetMixin

    通过上述代码结构分析,我们了解到只要知道ViewSetMixin是干嘛的,其他的类都继承于它。从源码中我们知道,ViewSetMixin重写了as_view()方法,源码如下:

    def as_view(cls, actions=None, **initkwargs):
        """
        由于基于类的视图围绕实例化视图创建闭包的方式,我们需要完全重新实现`.as_view`,并稍微修改创建和返回的视图函数。 
        对于某些路由配置,initkwargs 的名称和描述可能会被明确覆盖,例如,额外操作的名称。
        """
        # 名称和描述 initkwargs 可能会被显式覆盖
        cls.name = None
        cls.description = None
        
        # 后缀 initkwarg 保留用于显示视图集类型。如果提供了名称,则此 initkwarg 应该无效。
        cls.suffix = None
    
        cls.detail = None
        
        # 设置 basename 允许视图反转其操作 url。该值由路由器通过 initkwargs 提供。
        cls.basename = None
        
        # actions必须不能为空,否则报错
        if not actions:
            raise TypeError("The `actions` argument must be provided when "
                            "calling `.as_view()` on a ViewSet. For example "
                            "`.as_view({'get': 'list'})`")
    
        # 清理关键字参数
        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和suffix是互斥的
        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)
    
            if 'get' in actions and 'head' not in actions:
                actions['head'] = actions['get']
    
            self.action_map = actions
            
            # 将方法绑定到actions, 这是与标准视图不同的一点
            for method, action in actions.items():
                handler = getattr(self, action)
                setattr(self, method, handler)
    
            self.request = request
            self.args = args
            self.kwargs = kwargs
    
            return self.dispatch(request, *args, **kwargs)
    
        update_wrapper(view, cls, updated=())
    
        update_wrapper(view, cls.dispatch, assigned=())
    
        view.cls = cls
        view.initkwargs = initkwargs
        view.actions = actions
        return csrf_exempt(view)
    

    从上述源码中了解到,ViewSetMixin重写了as_view方法,as_view是将请求的方法绑定到了actions
     

    ViewSet

    class ViewSet(ViewSetMixin, views.APIView):
        """
        默认情况下,基本 ViewSet 类不提供任何操作。
        """
        pass
    

    ViewSet继承了ViewSetMixinAPIView,增删改查需要我们自己定义
     

    GenericViewSet

    class GenericViewSet(ViewSetMixin, generics.GenericAPIView):
        """
        GenericViewSet 类默认不提供任何操作,但包含通用视图行为的基本集,例如`get_object` 和`get_queryset` 方法。
        """
        pass
    

    GenericViewSet类相比ViewSet,包含了一些视图行为的通用方法
     

    视图集特点

    1. 视图集都是优先继承ViewSetMixin类,再继承一个视图类(GenericAPIView或APIView)
    2. ViewSetMixin提供了重写的as_view()方法,继承视图集的视图类,配置路由时调用as_view()必须传入 请求-函数名 映射关系字典
      eg: path('v1/books/<int:pk>/', views.BookGenericViewSet.as_view({"get": "my_get_obj"}))
       

    GenericAPIView与APIView 作为两大继承视图的区别

    1. GenericViewSetViewSet都继承了ViewSetMixinas_view都可以配置 请求-函数 映射
    2. GenericViewSet继承的是GenericAPIView视图类,用来完成标准的model类操作接口
    3. ViewSet继承的是APIView视图类,用来完成不需要model类参与,或是非标准的model类操作接口
      post请求在标准的model类操作下就是新增接口,登陆的post不满足
      post请求验证码接口,不需要model类的参与
      案例:登陆的post请求,并不是完成数据的新增,只是用post提交数据,得到的结果也不是登陆的用户信息,而是登陆的认证信息
       

    ReadOnlyModelViewSet

    class ReadOnlyModelViewSet(mixins.RetrieveModelMixin,
                               mixins.ListModelMixin,
                               GenericViewSet):
        """
        提供默认`list()` 和`retrieve()` 操作的视图集。
        """
        pass
    

    ModelViewSet

    class ModelViewSet(mixins.CreateModelMixin,
                       mixins.RetrieveModelMixin,
                       mixins.UpdateModelMixin,
                       mixins.DestroyModelMixin,
                       mixins.ListModelMixin,
                       GenericViewSet):
        """
        一个提供默认 `create()`、`retrieve()`、`update()`、`partial_update()`、`destroy()` 和 `list()` 操作的视图集。
        """
        pass
    

    实战案例

    视图函数如下

    class StudentViewSets(viewsets.ModelViewSet):
        queryset = Student.objects.all()
        serializer_class = StudentModelSerializer
        def my_get(self, request, *args, **kwargs):
            response =  self.retrieve(request, *args, **kwargs)
            return APIResponse(results=response.data)
    
        def my_list(self, request, *args, **kwargs):
            response = self.list(request, *args, **kwargs)
            return APIResponse(results=response.data)
    

    我们继承自ModelViewSet,自带5个mixins工具,我们定义了2个查询方法,然后在urls中配置

    urlpatterns = [
        path('v2/student/<int:pk>/', views.StudentViewSets.as_view({"get": "my_get"})),
        path('v2/student/', views.StudentViewSets.as_view({"get": "my_list"})),
    ]
    

    as_view中添加了get请求方式的方法,有pk调用my_get代表单查,没有pk调用my_list代表群查,这样写的原因就是我们的StudentViewSets继承了ViewSetMixin

  • 相关阅读:
    sdn&openswitch速查
    此博客已迁移【又要迁回来...】
    设计模式 之 里氏代换原则 (Liskov's Substitution Principle)
    设计模式 之 单一职责原则 (Single Responsibility Principle)
    设计模式 之 接口隔离原则 (Interface Segregation Principle)
    设计模式 之 依赖倒置原则 (Dependency Inversion Principle)
    设计模式 之 开放封闭原则 (Open Close Principle)
    设计模式 之 引言
    git && github
    book-rev8 Chapter 0 Operating system interfaces
  • 原文地址:https://www.cnblogs.com/jiakecong/p/14870383.html
Copyright © 2011-2022 走看看