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的本质的更多相关文章

  1. Django生命周期 URL ----> CBV 源码解析-------------- 及rest_framework APIView 源码流程解析

    一.一个请求来到Django 的生命周期   FBV 不讨论 CBV: 请求被代理转发到uwsgi: 开始Django的流程: 首先经过中间件process_request (session等) 然后 ...

  2. 2.CBV和类视图as_view源码解析

    一.FBV和CBV # 视图基于函数开发 FBV: function.base.views # 视图基于类开发 CBV: class .base .views #Python是一个面向对象的编程语言, ...

  3. django之admin源码解析

    解析admin的源码 第一步:项目启动,加载settings文件中的 INSTALLED_APPS 里边有几个app就加载几个,按照注册顺序来执行. 第二步:其中加载的是admin.py,加载每一个a ...

  4. CBV流程之View源码解析

    CBV是基于反射实现根据请求方式不同,执行不同的方法. 请求流程:view源码解析 1.urls.py :请求一定来执行视图下的as_view方法.也可以直接点击as_view()来找源码. 2.vi ...

  5. CBV源码与APIView源码解析

    一.CBV源码解析 在我们写cbv的时候在url中和fbv的区别就是是否调用了as_view()方法,所以关键入手点就是这个方法 @classonlymethod # 这是类的绑定方法,这个cls是我 ...

  6. django -admin 源码解析

    admin源码解析 单例模式 单例模式(Singleton Pattern)是一种常用的软件设计模式,该模式的主要目的是确保某一个类只有一个实例存在.当你希望在整个系统中,某个类只能出现一个实例时,单 ...

  7. Django框架 之 admin管理工具(源码解析)

    浏览目录 单例模式 admin执行流程 admin源码解析 单例模式 单例模式(Singleton Pattern)是一种常用的软件设计模式,该模式的主要目的是确保某一个类只有一个实例存在.当你希望在 ...

  8. Django 之 admin组件使用&源码解析

    admin组件使用 Django 提供了基于 web 的管理工具. Django 自动管理工具是 django.contrib 的一部分.可以在项目的 settings.py 中的 INSTALLED ...

  9. Django settings源码解析

    Django settings源码 Django中有两个配置文件 局部配置:配置文件settings.py,即项目同名文件夹下的settings.py文件 全局配置:django内部全局的配置文件se ...

随机推荐

  1. 【HTML+CSS】在书写代码时的便捷应用

    创建多个相同元素: <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> < ...

  2. Linux系统 Cetos 7 中重置root密码

    几个月前在自己电脑上面安装了一个Linux 的虚拟机环境,当时是为了测试某一个小功能,用完就扔那里了,长时间没有使用,发现Root密码忘记了,登陆不了,怎么办呢?(ps:如果实际情况中忘记密码的这个服 ...

  3. windows系统下升级nodejs

    别整那些有的没得,直接Win+R 输入:npm config ls 找到nodejs安装路径 然后上nodejs官网,下载最新安装程序,指定旧版本目录,直接安装覆盖掉 啥用n模块啥得,不适合俺们微软体 ...

  4. Linux-I/O重定向和管道

    Linux I/O重定向 标准输入(stdin):文件描述符0 标准输入(stdout):文件描述符1 标准错误(stderr):文件描述符2 file descriptors(FD,文件描述符 或 ...

  5. vscode笔记(一)- vscode自动生成文件头部注释和函数注释

    VsCode 自动生成文件头部注释和函数注释 作者:狐狸家的鱼 本文链接:vscode自动生成文件头部注释和函数注释 GitHub:sueRimn 1.安装插件KoroFileHeader 2.设置 ...

  6. github+jekyll个人博客搭建

    Thanks to https://blog.csdn.net/Hanghang_/article/details/78944672 跟着这个博客一步步搭建,从jekyll官网上找到自己喜欢的主题. ...

  7. 浅谈JS中逗号运算符的用法

    阅读本文的前提是,你能区分什么是表达式,什么是语句.还有明确运算符和运算数都是些啥东西.所谓的表达式就是一个JavaScript的"短语",JavaScript的解释器可以计算它, ...

  8. ansible迭代/迭代嵌套/同步异步/特殊topic说明

    tasks直接举例说明: ---- host: docker  remote_user: root  gather_facts: yes  serial: 3 #表示同一时间控制主机数量(值可以是数值 ...

  9. 如何将Windows电脑桌面上软件图标下的文字去掉

    如何将Windows电脑桌面上软件图标下的文字去掉 重命名的时候,点击鼠标右键.选择“插入Unicode控制字符” 效果

  10. Jenkins-在windows上配置自动化部署(Jenkins+Gitblit)

    Jenkins-在windows上配置自动化部署(Jenkins+Gitblit) 1. 安装好 Jenkins(注:安装目录需没有空格,否则安装gitlab hook 插件时会报错,安装在c盘跟目录 ...