源码解析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 ...
随机推荐
- OpenJudge-bailian 3454 秦腾与教学评估
http://bailian.openjudge.cn/practice/3454?lang=en_US 题目 在秦腾进入北京大学学习的第一个学期,就不幸遇到了前所未有的教学评估.在教学评估期间,同学 ...
- Leetcode 4.28 Tree Easy
1. 101. Symmetric Tree 用递归. class Solution { public boolean isSymmetric(TreeNode root) { if( root == ...
- .Net Core实践4 web 反向代理
目标 将控制台程序改成web程序,通过IIS反向代理,处理请求 环境 win10 / .net core 2.1 / centos7 变成web程序 1.在新建的asp.net core控制台程序中添 ...
- [Storage]RPM series linux rescan disk / RPM系Linux重新扫描硬盘
echo "- - -" > /sys/class/scsi_host/host0/scan echo "- - -" > /sys/class/s ...
- zsh!oh-my-zsh! 好看的主题和插件以及我的.zshrc
题外话,由于clear每次打的很麻烦,可以直接使用ctrl+L清屏,和clear等效. First: 安装好zsh和oh-my-zsh Second: 接下来就可以开始享受了 主题:cloud 满 ...
- fork子进程
title: fork子进程 data: 2019/3/21 20:24:39 toc: true --- 这里实在学习socket编程前的小知识点,用来创建多个服务端 学习文档 函数可以有两个返回值 ...
- ELK 构建 MySQL 慢日志收集平台详解
ELK 介绍 ELK 最早是 Elasticsearch(以下简称ES).Logstash.Kibana 三款开源软件的简称,三款软件后来被同一公司收购,并加入了Xpark.Beats等组件,改名为E ...
- .NET技术-2.0. 操作数据库-EF
.NET技术-2.0. 操作数据库-EF 项目参见: EF安装配置 参见: https://www.cnblogs.com/1285026182YUAN/p/10772330.html https:/ ...
- zeppelin中连接hive和impala
连接Hive 新建interpreter default.driver = org.apache.hive.jdbc.HiveDriver default.url = jdbc:hive2://hos ...
- 文件的暂存(git add)
如果我们更改了之前已经被跟踪的main.c,然后执行git status $ git status On branch master Changes not staged for commit: (u ...