源码解析Django CBV的本质
Django CBV模式的源码解析
通常来说,http请求的本质就是基于Socket
Django的视图函数,可以基于FBV模式,也可以基于CBV模式。
基于FBV的模式就是在Django的路由映射表里进行url和视图函数的关联,而基于CBV的模式则是在views.py文件中定义视图类,在视图类中视图函数,如get,post,put,delete等
使用Django新建一个项目,新建一个路由映射
from django.conf.urls import url
from django.contrib import admin
from app01 import views
urlpatterns = [
url(r'^cbv/$',views.CBV.as_view())
]
对应的views.py文件内容:
from django.shortcuts import render,HttpResponse
from django.views import View
class CBV(View):
def get(self,request):
return HttpResponse("GET")
def post(self,request):
return HttpResponse("POST")
启动项目,使用浏览器请求URLhttp://127.0.0.1:8000/cbv/
,浏览器显示结果为:
请求到达Django会先执行Django中间件里的方法,然后进行进行路由匹配。
在路由匹配完成后,会执行CBV类中的as_view方法。
CBV中并没有定义as_view
方法,由于CBV继承自Django的View
,所以会执行Django的View类中的as_view方法
Django的View类的as_view方法的部分源码
class View(object):
"""
Intentionally simple parent class for all views. Only implements
dispatch-by-method and simple sanity checking.
"""
http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace']
def __init__(self, **kwargs):
"""
Constructor. Called in the URLconf; can contain helpful extra
keyword arguments, and other things.
"""
# Go through keyword arguments, and either save their values to our
# instance, or raise an error.
for key, value in six.iteritems(kwargs):
setattr(self, key, value)
@classonlymethod
def as_view(cls, **initkwargs):
"""
Main entry point for a request-response process.
"""
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)
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
# take name and docstring from class
update_wrapper(view, cls, updated=())
# and possible attributes set by decorators
# like csrf_exempt from dispatch
update_wrapper(view, cls.dispatch, assigned=())
return view
从View的源码可以看出,在View类中,先定义了http请求的八种方法
http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace']
在as_view方法
中进行判断,如果请求的方法没在http_method_names
中,则会抛出异常,这里的cls实际上指的是自定义的CBV类
接着as_view方法中又定义view方法,在view方法中对CBV类进行实例化,得到self对象,然后在self对象中封装浏览器发送的request请求
self = cls(**initkwargs)
最后又调用了self对象中的dispatch方法并返回dispatch方法的值来对request进行处理
此时,由于self对象就是CBV实例化得到,所以会先执行自定义的CBV类中的dispatch方法。如果CBV类中没有定义dispatch方法则执行Django的View中的dispatch方法
Django的View中的dispatch方法源码
class View(object):
"""
中间省略
"""
def dispatch(self, request, *args, **kwargs):
# Try to dispatch to the right method; if a method doesn't exist,
# defer to the error handler. Also defer to the error handler if the
# request method isn't on the approved list.
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)
在dispatch方法中,把request.method转换为小写再判断是否在定义的http_method_names中,如果request.method存在于http_method_names中,则使用getattr反射的方式来得到handler
在这里的dispatch方法中,self指的是自定义的CBV类实例化得到的对象
从CBV类中获取request.method对应的方法,再执行CBV中的方法并返回
由此,可以知道如果在Django项目中使用CBV的模式,实际上调用了getattr的方式来执行获取类中的请求方法对应的函数
结论:
CBV基于反射实现根据请求方式不同,执行不同的方法
自定义dispatch方法
如果想在基于CBV模式的项目中在请求某个url时执行一些操作,则可以在url对应的类中定义dispatch方法
修改views.py文件
class CBV(View):
def dispatch(self, request, *args, **kwargs):
func = getattr(self,request.method.lower())
return func(request,*args,**kwargs)
def get(self,request):
return HttpResponse("GET")
def post(self,request):
return HttpResponse("POST")
也可以使用继承的方式重写dispatch方法:
class CBV(View):
def dispatch(self, request, *args, **kwargs):
print("before")
res = super(CBV, self).dispatch(request, *args, **kwargs)
print("after")
return res
def get(self,request):
return HttpResponse("GET")
def post(self,request):
return HttpResponse("POST")
刷新浏览器,Django后台打印结果如下:
浏览器页面结果
同理,如果有基于CBV的多个类,并且有多个类共用的功能,为了避免重复,可以单独定义一个类,在这个类中重写dispatch方法,然后让url对应的视图类继承这个类
修改urls.py文件
from django.conf.urls import url
from django.contrib import admin
from app01 import views
urlpatterns = [
url(r'^cbv1/$',views.CBV1.as_view()),
url(r'^cbv2/$',views.CBV2.as_view()),
]
views.py文件内容
from django.shortcuts import render,HttpResponse
from django.views import View
class BaseView(object):
def dispatch(self, request, *args, **kwargs):
func = getattr(self, request.method.lower())
return func(request, *args, **kwargs)
class CBV1(BaseView,View):
def get(self,request):
return HttpResponse("CBV1 GET")
def post(self,request):
return HttpResponse("CBV1 POST")
class CBV2(BaseView,View):
def get(self,request):
return HttpResponse("CBV2 GET")
def post(self,request):
return HttpResponse("CBV2 POST")
通过python的面向对象可以知道,请求到达视图类时,会先执行CBV1和CBV2类中的dispatch方法,然而CBV1和CBV2类中并没有dispatch方法,则会按照顺序在父类中查找dispatch方法,此时就会执行BaseView类中的dispatch方法了
用浏览器请求urlhttp://127.0.0.1:8000/cbv1/
,浏览器页面显示
用浏览器请求urlhttp://127.0.0.1:8000/cbv2/
,浏览器页面显示
源码解析Django CBV的本质的更多相关文章
- Django生命周期 URL ----> CBV 源码解析-------------- 及rest_framework APIView 源码流程解析
一.一个请求来到Django 的生命周期 FBV 不讨论 CBV: 请求被代理转发到uwsgi: 开始Django的流程: 首先经过中间件process_request (session等) 然后 ...
- 2.CBV和类视图as_view源码解析
一.FBV和CBV # 视图基于函数开发 FBV: function.base.views # 视图基于类开发 CBV: class .base .views #Python是一个面向对象的编程语言, ...
- django之admin源码解析
解析admin的源码 第一步:项目启动,加载settings文件中的 INSTALLED_APPS 里边有几个app就加载几个,按照注册顺序来执行. 第二步:其中加载的是admin.py,加载每一个a ...
- CBV流程之View源码解析
CBV是基于反射实现根据请求方式不同,执行不同的方法. 请求流程:view源码解析 1.urls.py :请求一定来执行视图下的as_view方法.也可以直接点击as_view()来找源码. 2.vi ...
- CBV源码与APIView源码解析
一.CBV源码解析 在我们写cbv的时候在url中和fbv的区别就是是否调用了as_view()方法,所以关键入手点就是这个方法 @classonlymethod # 这是类的绑定方法,这个cls是我 ...
- django -admin 源码解析
admin源码解析 单例模式 单例模式(Singleton Pattern)是一种常用的软件设计模式,该模式的主要目的是确保某一个类只有一个实例存在.当你希望在整个系统中,某个类只能出现一个实例时,单 ...
- Django框架 之 admin管理工具(源码解析)
浏览目录 单例模式 admin执行流程 admin源码解析 单例模式 单例模式(Singleton Pattern)是一种常用的软件设计模式,该模式的主要目的是确保某一个类只有一个实例存在.当你希望在 ...
- Django 之 admin组件使用&源码解析
admin组件使用 Django 提供了基于 web 的管理工具. Django 自动管理工具是 django.contrib 的一部分.可以在项目的 settings.py 中的 INSTALLED ...
- Django settings源码解析
Django settings源码 Django中有两个配置文件 局部配置:配置文件settings.py,即项目同名文件夹下的settings.py文件 全局配置:django内部全局的配置文件se ...
随机推荐
- js判断iPhone XS、iPhone XS Max、iPhone XR
// iPhone X.iPhone XS && window.screen.width === && window.screen.height === ; // iP ...
- Linux几大服务
server0操作: 1.创建/devops目录,并修改其SELINUX安全上下文 # mkdir /devops # vim /devops/1.mp3# chcon -R -t samba_sha ...
- 一、操作m'y's'ql
一.创建framework框架的控制台默认不支持mysql
- Manjaro折腾简单记录
0.Manjaro启动U盘的制作 推荐使用4-16G容量的U盘,避免兼容性问题(U盘太大可能会无法启动). 用rufus就可以,注意选用DD模式才能成功制作. 如果在linux环境里,先用sudo f ...
- mapper.xml 的配置
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "- ...
- Codeforces Round #534 (Div. 1)
A 构造题 有一个44的方格 每次放入一个横向12或竖向2*1的方格 满了一行或一列就会消掉 求方案 不放最后一行 这样竖行就不会消 然后竖着的放前两行 横着的放第三行 循环放就可以啦 #includ ...
- 使用sshpass同时更新一台ubuntu和一台CentOS
1.在ubuntu上安装sshpass sudo apt install sshpass 2.分别在两台的root路径下放上升级脚本: cent:/root/upgrade.sh #!/bin/bas ...
- [NOIP2017] 列队(平衡树)
考虑转化题意: 设这次操作删掉点\((x, y)\) 对于每一次向左看齐:在第x行删除\((x, y)\),并将y以后的点全部前移一位 对于每一次向前看齐:x以后的点全部上移一位,并在最后一列插入\( ...
- Spring Boot学习总结四
利用阿里的druid来管理数据库连接池,在此数据上针对多数据源的情况,做下讲解.首先加上该包 <dependency> <groupId>com.alibaba</gro ...
- .NET常用开发框架汇总
分布式缓存框架:Microsoft Velocity:微软自家分布式缓存服务框架.Memcahed:一套分布式的高速缓存系统,目前被许多网站使用以提升网站的访问速度.Redis:是一个高性能的KV数据 ...