APIView用法:
在Django之 CBV和FBV中,我们是分析的from django.views import View
下的执行流程,以下是代码
from django.views import View class IndexView(View): def get(self,request, *args, **kwargs): return HttpResponse("ok") def dispatch(self, request, *args, **kwargs): ret = super(IndexView,self).dispatch(request, *args, **kwargs) return HttpResponse(ret)
这篇博客我们就来了解下APIView
是如何执行的,跟django.views
模块下的view
有何关联?
我们依然从url配置入手分析
url(r"books/$",views.BookView.as_view())
as_view
方法代码如下
原来APIView
类是继承View
类,view
类正式from django.views import View下的View
,
先看as_view
方法中的view = super(APIView, cls).as_view(**initkwargs)
的这行代码,
是调用了父类View
中的as_view
方法,这里的initkwargs
,及其父类的View
中的as_view
方法执行流程,之类就不在赘述了
具体流程去看我博客开头的博客链接
所以在APIView
类中,我们重点看下return csrf_exempt(view)
做了什么操作?
def csrf_exempt(view_func): def wrapped_view(*args, **kwargs): return view_func(*args, **kwargs) wrapped_view.csrf_exempt = True return wraps(view_func, assigned=available_attrs(view_func))(wrapped_view)
wrapped_view.csrf_exempt = True
意思是取消当前函数防跨站请求伪造功能,即便settings中设置了全局中间件,然后将csrf_exempt
函数中的内置函数wrapped_view
赋值wrapped_view.csrf_exempt = True
,使其拥有该属性,
接下来看 wraps(view_func, assigned=available_attrs(view_func))(wrapped_view)
函数之前,
我们先看下assigned=available_attrs(view_func)
def available_attrs(fn): if six.PY3: return WRAPPER_ASSIGNMENTS else: return tuple(a for a in WRAPPER_ASSIGNMENTS if hasattr(fn, a))
大概意思就是针对py3
或者其他版本做了一些判断处理,最后通过WRAPPER_ASSIGNMENTS
定为到
WRAPPER_ASSIGNMENTS = (‘__module__‘, ‘__name__‘, ‘__qualname__‘, ‘__doc__‘, ‘__annotations__‘)
这个逻辑跟我们上一篇的CBV源码有共同之处,就是为某个方法或者函数,添加某些属性
接下来我们看wraps
函数吧
def wraps(wrapped, assigned = WRAPPER_ASSIGNMENTS, updated = WRAPPER_UPDATES): return partial(update_wrapper, wrapped=wrapped, assigned=assigned, updated=updated)
wrapped是我们在def csrf_exempt(view_func):
函数中的参数,也就是as_view
的返回值,
最后通过functools
模块下的partial
类进行装饰构造,partial 这个东西是针对函数起作用的,并且是部分的,
场景:有这样的函数:get_useragent(request) 用来获取用户浏览器的ua信息,但是这个函数又不是在主体函数(执行页面渲染的函数)get时调用的,只在模板中的一个filter中调用的(可以理解是在模板渲染时调用的),而filter在执行的时候是不能添加参数的,哪你要怎么处理。
这时partial就得闪亮登场,如下是代码,
def __new__(*args, **keywords): if not args: raise TypeError("descriptor ‘__new__‘ of partial needs an argument") if len(args) < 2: raise TypeError("type ‘partial‘ takes at least one argument") cls, func, *args = args if not callable(func): raise TypeError("the first argument must be callable") args = tuple(args) if hasattr(func, "func"): args = func.args + args tmpkw = func.keywords.copy() tmpkw.update(keywords) keywords = tmpkw del tmpkw func = func.func self = super(partial, cls).__new__(cls) self.func = func self.args = args self.keywords = keywords return self def __call__(*args, **keywords): if not args: raise TypeError("descriptor ‘__call__‘ of partial needs an argument") self, *args = args newkeywords = self.keywords.copy() newkeywords.update(keywords) return self.func(*self.args, *args, **newkeywords)
最后在csrf_exempt
函数中的wraps(view_func, assigned=available_attrs(view_func))(wrapped_view)这里写代码片
传入参数wrapped_view
,通过对象可调用功能,进行调用__call__
方法
到此as_view
分析完毕,以上代码好多有迷惑的点,我分析的时候也是很多猜想的
上篇CBV
源码分析中我们知道,当as_view
执行后,当浏览器访问某个api接口时候,
就会先触发dispatch
,然后在dispatch
中,如下是父类的dispatch
方法
def dispatch(self, request, *args, **kwargs): # Try to dispatch to the right method; if a method doesn‘t exist, # defer to the error handler. Also defer to the error handler if the # request method isn‘t on the approved list. if request.method.lower() in self.http_method_names: handler = getattr(self, request.method.lower(), self.http_method_not_allowed) else: handler = self.http_method_not_allowed return handler(request, *args, **kwargs)
然而API
方法中也有自己的dispatch
方法,会执行子类的方法,而不是去执行父类的dispatch
方法,以下是代码
以上dispatch
方法中,通过self.initialize_request(request, *args, **kwargs)
新的request中
通过initialize_request
进一步分装成自己的Request
类
然后self.initial(request, *args, **kwargs)
,
完善request
请求的一些注意事项,例如用户登录、检测权限等等
然后response = handler(request, *args, **kwargs)
这里面是执行了对应的请求操作,如get\post
请求,也就是执行了我们自定义视图里面的get方法等,在处理完毕后,赋值response
然后作为参数进行如下的操作
随后self.response = self.finalize_response(request, response, *args, **kwargs)
返回,这一部操作,跟它的父类View
是不同的,
在继承APIView的视图中,get\post需要返回HttpResponse
,然后在通过self.finalize_response
进一步封装,最后返回
最后在dispatch
中
self.response = self.finalize_response(request, response, *args, **kwargs) return self.response
原文地址:https://www.cnblogs.com/95lyj/p/9434221.html