源码解析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 ...
随机推荐
- CF 1119C Ramesses and Corner Inversion
https://codeforces.com/problemset/problem/1119/C 题目 给两个矩阵,只能选宽和高大于等于2的子矩阵左上.左下.右上.右下四点翻转(1->0,0-& ...
- ORACLE数据闪回
ALTER TABLE SPM_CON_PAYMENT_RECEIPT ENABLE ROW MOVEMENT; -- 表名 FLASHBACK TABLE SPM_CON_PAYMENT_REC ...
- 上板子在线抓波发现app_rdy一直为低
现象 使用Xilinx的MIG IP测试外挂DDR3的读写发现一段很短的时间后app_rdy恒为低,并且最后一个读出的数据全是F. (1)不读写数据,app_rdy正常为高,MIG IP初始化信号为高 ...
- mac 下 clang++ 找不到头文件 stdlib.h
因为要用 openmp库,用 clang++ 编译 c++程序,出现了如下报错: clang++ xx.cpp -o xx -fopenmp /usr/local/Cellar/llvm/7.0.0/ ...
- [十二省联考2019]异或粽子(堆+可持久化Trie)
前置芝士:可持久化Trie & 堆 类似于超级钢琴,我们用堆维护一个四元组\((st, l, r, pos)\)表示以\(st\)为起点,终点在\([l, r]\)内,里面的最大值的位置为\( ...
- SQL2012数据库还原失败System.Data.SqlClient.SqlError: 无法执行 BACKUP LOG,因为当前没有数据库备份
在一次数据库还原的操作过程中遇到如上错误,去百度了下找到了对应的解决方法 第一个: 在还原完整备份时候,在回复状态状态哪里选择 restore with norecovery ,尾日志部分可选可不选, ...
- 关于word-break和word-wrap的使用和区别
当一段文字有一个长长长的英文单词的情况下使用这两个属性的区别: word-wrap: 哈哈哈, aaaaa bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb word-break: ...
- elasticsearch 介绍
一.什么是elasticsearch Elasticsearch是一个基于Lucene的高度可伸缩的分布式的开源全文搜索和分析引擎.它允许您快速.实时地存储.搜索和分析大量数据.它通常用作底层引擎/技 ...
- linux 命令之文件读取,head, tail, tailf, sed
head 看文件的前100行head -100 filename tail/tailf查看文件的后100行tail -100 filename 或 tail -n 100 filename ta ...
- python之路(11)描述符
前言 描述符是用于代理另一个类的属性,一般用于大型的框架中,在实际的开发项目中较少使用,本质是一个实现了__get__(),__set__(),__delete__()其中一个方法的新式类 __get ...