CBV_____dispatch()
django视图一般分为FBV和CBV,这里主要介绍CBV的主要流程
CBV的逻辑流程为
1.url--执行 as_view()
2.as_view()返回view()
3.view() 返回 dispatch()
也就是说,所有的请求最后都是通过dispatch()处理的,下面举例说明dispatch是如何工作的
1.父类的dispatch理解
urls代码:
from django.urls import path from . import views urlpatterns = [ path('cbv/',views.CbvView.as_view()), ]
views代码:
from django.http import HttpResponse from django.views import View class CbvView(View): def get(self,request,*args,**kwargs): return HttpResponse('cbv的get请求') def post(self,request,*args,**kwargs): return HttpResponse('cbv的post请求')
前面已经整理到CBV的逻辑流程,最后都是执行的dispatch方法,这里贴下dispatch源码:
def dispatch(self, request, *args, **kwargs): #由于request.method返回的都是大写的请求类型,如GET,所以需要小写处理 #基于反射,如果self的请求类型在http_method_names里面,则执行self的对应方法 #如:假如请求是post方法,然后post在http_method_names里面,然后返回self(也就是CbvView)的post方法,然后根据我们定义的post方法的逻辑进行处理 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)
测试一下情况:
当发送get请求的时候,由于request.method为GET,所以查看dispatch中的代码等同于 handler = getattr(CbvView,'get'),最后return出来的是 CbvView的get方法,如下图:
同理,当请求为post时,如下图:
2.尝试重写父类的dispatch方法
在CBV类中直接重写父类的dispatch方法,这样就不会去执行父类的dispatch了
views代码修改如下:
class CbvView(View): def dispatch(self,request,*args,**kwargs): return HttpResponse('子类中重写的dispatch') def get(self,request,*args,**kwargs): return HttpResponse('cbv的get请求') def post(self,request,*args,**kwargs): return HttpResponse('cbv的post请求')
然后这时候调用不管是用get请求还是post请求,得到的返回都是 "子类中重写的dispatch"
这里再一次理下逻辑
1.路由中去执行CbvView的as_view()方法,但是CbvView类中没有这个方法,所以去父类中找
2.父类View中as_view()方法经过一系列处理之后返回的是self.dispatch()方法,这里的self指的是CbvView,所以下一步去CbvView中找dispatch方法
3.由于我们在子类CbcView中重写了disptch方法,所以执行子类的该方法,又由于我们这里直接是返回 HttpResponse('子类中重写的dispatch'),
所以不管请求是什么类型,只要请求过来,都是return的 "子类中重写的dispatch"
PS:这里重写的dispatch和源码自带的dispatch不一样,这里更好的理解源码中的dispatch ,是经过了一次请求method判断,然后根据判断的类型,handler就是反射
得到CBV类中对应的函数,(请求methdod是GET 就反射得到CbvView中的get方法)
测试如图:
3.继承
用CBV写视图函数其中最大的好处就是可以试用面向对象的特性,比如对某一些视图,都需要做到某一个操作,这时候可以把这个操作封装起来,然后需要用到该操作的视图都继承于
该类,这样就不用每个视图类中取重复编码了
举例说明:
views文件修改如下:
from django.http import HttpResponse class MyBase_View(object): def dispatch(self,request,*args,**kwargs): print('这里可以写一些公用的操作,所有继承该类的视图函数 就不用重复编码了') #由于所有继承该类的都是CBV视图类,会多重继承,多重继承关系中兄弟节点也是可以继承的,所以这里的dispatch会去View中继承 ret = super(MyBase_View,self).dispatch(request,*args,**kwargs) return ret class CbvView(MyBase_View,View): # def dispatch(self,request,*args,**kwargs): # # return HttpResponse('子类中重写的dispatch') # #这里多继承,优先MyBaseView # ret=super(CbvView,self).dispatch(request, *args, **kwargs) # return ret def get(self,request,*args,**kwargs): return HttpResponse('cbv的get请求') def post(self,request,*args,**kwargs): return HttpResponse('cbv的post请求')
接下来不管我们发送什么请求,控制台都会先打印MyBase_View中输出的语句,然后正常执行我们视图类中的各个请求逻辑。
如图: