您的位置:首页 > 编程语言 > Go语言

Django(58)viewsets视图集详解

2021-06-10 16:57 1116 查看

前言

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

源码分析

我们首先看一下

viewsets.py
文件的源码结构,如下图 我们可以看到有5个类

  • ViewSetMixin
  • ViewSet:继承自
    ViewSetMixin
    APIView
  • GenericViewSet:继承自
    ViewSetMixin
    GenericAPIView
  • ReadOnlyModelViewSet:继承自
    RetrieveModelMixin
    ListModelMixin
    GenericViewSet
  • 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
继承了
ViewSetMixin
APIView
,增删改查需要我们自己定义  

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. GenericViewSet
    ViewSet
    都继承了
    ViewSetMixin
    as_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

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: