一、CBV与FBV
#Class Base View(基于类的视图) #Function Base View(基于函数的视图)
二、CBV的用法及源码分析
1、用法
#视图层 # 1 先导入View(继承它) from django.views import View # 写一个类继承它, class Test(View): #request必须传,后面的可传可不传(有可能有名,无名分组) def get(self, request, *args, **kwargs): print('get') return render(request, 'login.html') def post(self, request): name = request.POST.get('name') pwd = request.POST.get('pwd') if name == 'pdun' and pwd == '123': return HttpResponse('登录成功') else: return render(request, 'login.html', {'error': '用户名或密码错误'}) #路由层 urlpatterns = [ # as_view一定要加括号,as_view()哪里来的? 从View中继承过来的 # as_view用类来调用的,它是一个类方法 # 猜:as_view这个方法执行完成以后,应该是个函数的内存地址 # 如果是get请求,会响应到类内部,执行get方法post请求,一样 # as_view 类方法,自动把自己传过来 url(r'^login/', views.Test.as_view()), #模板层与FBV相同 <body> <form action="" method="post"> <p>用户名: <input type="text" name="name"></p> <p>密码: <input type="password" name="pwd"></p> <p><input type="submit" value="提交">{{ error }}</p> </form> </body>
2、源码分析
#View类中有1个数据属性,6个方法属性 class View(object): http_method_names = ['get', 'post', ' 'trace'。。。] def __init__(self, **kwargs): @classonlymethod def as_view(cls, **initkwargs): def view(request, *args, **kwargs): def dispatch(self, request, *args, **kwargs): def http_method_not_allowed(self, request, *args, **kwargs): def options(self, request, *args, **kwargs): def _allowed_methods(self):
路由层as_view #调用顺序: 请求来了---->as_view --> view --> dispatch----->分发到不同的函数(自己写的类中的get,post) 可以看出as_view实际上是一个闭包,他的作用就是做一些检验工作,再返回view方法 而view方法的作用是给请求对象补充三个参数,并调用dispatch方法处理 dispatch方法查找到指定的请求方法,并执行相应代码块 #可以得出结论:as_view方法实际上最后就是要调用dispatch方法
#路由 url(r'^login/', views.Login.as_view()),
class View(object): http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace'] @classonlymethod def as_view(cls, **initkwargs): def view(request, *args, **kwargs): #这是一个闭包函数 self = cls(**initkwargs) #判断self类中是不是有该(get)方法 if hasattr(self, 'get') and not hasattr(self, 'head'): self.head = self.get self.request = request #这几个是赋值 self.args = args self.kwargs = kwargs #最后执行的是dispatch方法,自己的类中一般不重写这个方法,所以执行view的中的该方法 return self.dispatch(request, *args, **kwargs) view.view_class = cls view.view_initkwargs = initkwargs return view def dispatch(self, request, *args, **kwargs): #request.method 前台请求的方法,转成了小写并判断在不在列表中 if request.method.lower() in self.http_method_names: #getattr的第三个参数是默认值:self.http_method_not_allowed #拿到get方法的内存地址 handler = getattr(self, request.method.lower(), self.http_method_not_allowed) else: handler = self.http_method_not_allowed return handler(request, *args, **kwargs)
#闭包函数,内部函数包含外部函数的名称空间 def bar(): x=8 y=8 def inner(): q=x+y print(q) inner.x=1 #注意这里,不是更改X print(inner.__dict__) return inner bar()() {'x': 1} 16
#读源码总结 #CBV:基于类的视图 #导入from django.views import View #自定义类继承View #自定义的类中只能是如下方法: #http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace'] #请求流程:as_view() 的返回值是他内部view函数的内存地址 #dispatch方法,总的分发方法 #补充:装饰器的装饰方法 url(r'^test/', csrf_exempt(views.test)), #总结: #路由配置好,项目启动:as_view()---->返回结果是一个函数的内存地址 #请求来了---->触发函数的执行,就会执行dispatch方法---->根据请求的不同,分发到不同的视图函数