文章目录
一、CBV和FBV二、CBV 源码分析一个视图函数(类),简称视图,是一个简单的Python 函数(类),它接受Web请求并且返回Web响应。
响应可以是一张网页的HTML内容,一个重定向,一个404错误,一个XML文档,或者一张图片。
无论视图本身包含什么逻辑,都要返回响应。代码写在哪里也无所谓,只要它在你当前项目目录下面。除此之外没有更多的要求了——可以说“没有什么神奇的地方”。为了将代码放在某处,大家约定成俗将视图放置在项目(project)或应用程序(app)目录中的名为views.py
的文件中。
一、CBV和FBV
FBV:基于函数的视图;
CBV:基于类的视图;
FBV版添加班级
def add_class(request):if request.method == "POST":class_name = request.POST.get("class_name")models.Classes.objects.create(name=class_name)return redirect("/class_list/")return render(request, "add_class.html")
CBV版添加班级
注意:CBV 需要继承
view
类
from django.views import Viewclass AddClass(View):def get(self, request):return render(request, "add_class.html")def post(self, request):class_name = request.POST.get("class_name")models.Classes.objects.create(name=class_name)return redirect("/class_list/")
使用CBV时,urls.py
中也做对应的修改:
# urls.py中url(r'^add_class/$', views.AddClass.as_view()),
基于 CBV 与 FBV 的不同之处,分析CBV 的运行原理
二、CBV 源码分析
使用 CBV 时,需要 通过视图类. as_view()
才能进行路由匹配,那么直接观察这个as_view()
的源码
首先,
as_view()
是一个绑定给 类的方法其次,由于
url
中是加上括号调用了as_view()
,所以,观察返回值能够发现,返回的是内部的一个view
函数
**至此,我们简化一下,AddClass.as_view()
运行的结果就是view
; 所以views.AddClass.as_view()
=views.view
**
# urls.py中其本质就是url(r'^add_class/$', views.view),
所以 CBV 路由匹配的本质,就是 FBV
接下来,我们分析一下,当路由匹配成功时,需要执行的这个view
函数的源码
from django.views import Viewclass AddClass(View):def get(self, request):return render(request, "add_class.html")def post(self, request):class_name = request.POST.get("class_name")models.Classes.objects.create(name=class_name)return redirect("/class_list/")
@classonlymethoddef as_view(cls, **initkwargs):... ... # 源码省略def view(request, *args, **kwargs):self = cls(**initkwargs) -----> '实例化生成一个对象'if hasattr(self, 'get') and not hasattr(self, 'head'): self.head = self.get ----> '给生成的对象添加 head 属性'self.request = request ----> '给生成的对象添加 request 属性'self.args = args ----> '给生成的对象添加 args 属性'self.kwargs = kwargs ----> '给生成的对象添加 args 属性'return self.dispatch(request, *args, **kwargs) ... ... # 源码省略return view
最为重要的部分就是return self.dispatch(request, *args, **kwargs)
由于,对象 和 产生对象的
AddClass
类中都没有dispatch
函数,所有需要到AddClass
的父类view
中去找
http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace']def dispatch(self, request, *args, **kwargs):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_allowedreturn handler(request, *args, **kwargs)
判断当前请求的方法是否符合 8 个 默认的请求方法
getattr( 对象, 请求的方法(字符串), 拿不到请求方法的报错信息)
--> 拿到了AddClass
我们自定义类的get
方法最后一步就是 执行了 我们自定义的
get
方法