Django视图CBV的dispatch相关源码解析
一般cbv视图写法:
class Foo(View):
def get(request):
return HttpResponse('GET')
一般路由写法:
urlpatterns = [
url(r‘^index/‘, views.index),
url(r‘^index/‘, views.Index.as_view()),
]
Django在通过路由as_view()方法,会执行基类View中的dispatch方法,在通过dispatch方法执行具体的方法视图。
在这个方法中会先判断这个请求的method是否在http_metod_names列表中。
http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace']
这个列表是http协议中的请求方法,我们也可以通过修改源码,自定义请求类型。
然后dispatch通过getattr,从self这个对象中找method方法(小写,因为我们试图类里都是小写的方法名),找到之后运行并传参。
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)
由上面这个源码原理我们具体分析dispatch运行过程如下:
from django.views import View
class StudentView(View):
def dispatch(self,request,*args,**kwargs):
ret =super(StudentView,self).dispatch(request,*args,**kwargs)
return ret
def get(self,request,*args,**kwargs):
return HttpResponse('GET')
总结:
1 通过视图的as_view()运行源码as_view()
as_view会return dispatch这个方法
2 执行 Student类里自己的dispatch,因为我们重写了这个方法,所以先运行自己的。
自己的这个dispatch通过super找到了源码的dispatch.
3 源码的dispatch先判断请求的method是否在http_method_names ,
然后通过反射getattr,找到method,这个method又回到了Student类里的具体的method方法。
4 最后运行我们重写的dispatch中的return ret返回给用户。
所以我们重写的这个dispatch的原理就有点像装饰器,如果我们在super之前写一个print('before'),return之前写一个print('after'),那么每次浏览器请求之前都会先打印before,返回给用户之前都会打印after。
示例如下:
from django.views import View
class StudentView(View):
def dispatch(self,request,*args,**kwargs):
print('before')
ret =super(StudentView,self).dispatch(request,*args,**kwargs)
print('after')
return ret