CBV—基于类的视图
CBV基本写法:
views.py中的写法:
from django.conf.urls import url
from django.contrib import admin
from django.views import View
class MyLogin(View): # 这里的MyLogin是我们自定义的CBV类
def get(self, request):
return render(request, 'login.html')
def post(self, request):
return HttpResponse('我是类里面的post方法')
url写法:
url(r'^login/', views.MyLogin.as_view())
login.html中的代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>
<link href="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet">
<script src="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script>
</head>
<body>
<form action="" method="post">
{% csrf_token %}
<input type="submit">
</form>
</body>
</html>
启动项目,使用浏览器请求url: 127.0.0.1:8000/login/,显示结果为(此时为GET请求)
当点击提交按钮后,由login.html代码中可见form表单使用的是POST请求,获得如下结果:
请求达到django会先执行django中间件里的方法,然后执行路由匹配。
在路由匹配完成后,会执行CBV类中的as_view方法。
但是此时,我们定义的类中并没有as_view方法,所以会接着到它的父类View中寻找并使用父类中的as_view方法。
django中View类的部分源码:
class View(object):
http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace']
def __init__(self, **kwargs):
for key, value in six.iteritems(kwargs):
setattr(self, key, value)
@classonlymethod
def as_view(cls, **initkwargs): # cls是我们自己写到的MyLogin类
for key in initkwargs:
if key in cls.http_method_names:
raise TypeError("You tried to pass in the %s method name as a "
"keyword argument to %s(). Don't do that."
% (key, cls.__name__))
if not hasattr(cls, key):
raise TypeError("%s() received an invalid keyword %r. as_view "
"only accepts arguments that are already "
"attributes of the class." % (cls.__name__, key))
def view(request, *args, **kwargs):
self = cls(**initkwargs) # cls是我们自己写到的MyLogin类
if hasattr(self, 'get') and not hasattr(self, 'head'):
# 以下四句话,是在给我们自己写的类产生的对象设置属性
self.head = self.get
self.request = request
self.args = args
self.kwargs = kwargs
# 对象查找属性和方法的顺序,先从对象自身找,再从产生对象的类、父类中查找
return self.dispatch(request, *args, **kwargs)
view.view_class = cls
view.view_initkwargs = initkwargs
update_wrapper(view, cls, updated=())
update_wrapper(view, cls.dispatch, assigned=())
return view
def dispatch(self, request, *args, **kwargs):
if request.method.lower() in self.http_method_names:
# handler = getattr(我们自己写的类产生的对象,'get',报错信息
# handler就是我们自己类里面的get方法
handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
else:
handler = self.http_method_not_allowed
return handler(request, *args, **kwargs)
# 调用类里面的get方法
从view中的源码可以看出,再View类中,先定义了http请求的八种方法
http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace']
在【as_view】方法中进行判断,如果请求的方法没在 【http_method_names】中,则会抛出异常,
@classonlymethod
def as_view(cls, **initkwargs): # cls是我们自己写到的MyLogin类
【as_view】方法中又定义了view方法,在view方法中对CBV类进行实例化,并为其设置属性,向浏览器发送request请求。
最后调用【dispatch】方法并返回【dispatch】方法的值来对request进行处理:
由于self对象就是CBV实例化得到,所以会先执行自定义的CBV类中的dispatch方法。如果CBV类中没有定义dispatch方法则执行Django的View中的dispatch方法