最近一直用Django开发项目,在项目的视图中使用到了Django的View类和ListView类。
from django.views.generic import View, ListView
在使用过程中,发现Django的View类中有两个方法可以重写,分别是get()和post()。
当我们继承View类,并重写上述的两个方法时,View类就能够自动根据request请求中的method类型自动调用相应的方法。
比如,打开登录页面。
路径:../login/
method:GET
urls:path(‘login/’, view.LoginView.as_view())
views:
class LoginView(View): template_name = 'login.html'
通过以上代码,就完成了打开登录页面相关代码的编写。
再比如,打开登录页面之后的登录验证。
路径:../login/
method:POST
urls:path(‘login/’, views.LoginView.as_view())
views:
class LoginView(View): template_name = 'shop/login.html' def post(self, request): ...此处省略登录验证的代码...
大家能够看到,登录验证的路径和URL配置没有任何改变,只是请求方法变成了“POST”,并且在视图中重写“post()”方法就可以了。
一般来说,我们在写视图函数时,URL配置中都是“views.视图函数名称”,例如,“views.login”。
而使用Django的View类时,URL配置中都是“views.视图类名称.as_view()”,例如,“views.LoginView.as_view()”。
这里很容易让人产生矛盾,为什么一个没有括号,一个有括号?
我们知道,一个没有括号的函数名称,表示一个函数对象;而有括号的函数名称是函数对象被执行。
“views.login”是视图模块中的函数对象,当收到request请求时,会将request作为参数执行这个函数。
那为什么使用Django的View类时,URL配置中不是函数对象,而是执行了一个函数呢?
实际上执行的“as_view()”是一个类方法(classmethod),它会返回一个函数对象(闭包)。
下面,我通过一段代码给大家简单的模拟一下基本原理。
示例代码:
class SiteBaseView: template_name = '' # 定义模板名称的类变量 def get(self, request): # 与request请求类型同名的方法 return render(request, self.template_name) def post(self, request): # 与request请求类型同名的方法 pass def dispatch(self, request): # 5B.被执行的调度方法 method = getattr(self, request.method.lower()) # 6.获取与request请求类型同名的方法对象 return method(request) # 7.执行方法对象并返回执行结果 @classmethod def as_view(cls): # 1.urls中执行的类方法 def view(request): # 3.被返回的函数对象 self = cls() # 4.创建类对象 response = self.dispatch(request) # 5A.执行类对象中的调度方法 return response # 8.返回响应结果 return view # 2.返回函数对象
完成以上代码后,我们就可以在定义视图类时,像继承Django的View类一样,继承我们自己写的“SiteBaseView”类。
示例代码:
class LoginView(SiteBaseView): template_name = 'shop/login.html' def post(self, request): ...此处省略登录验证的代码...
最终的运行效果是一样的。
不过,在这里我只是通过简单的代码来模拟实现原理,Django的View类要比上面的代码复杂得多,大家可以通过研究Django的源代码学到更多有用的知识。
本文链接:http://so.lmcjl.com/news/2093/