django中的FBV 和 CBV

在django中视图有两种写法,一种是FBV,另外一种是CBV。

FBV是function based view的意思,就是说view中都是定义的函数来实现的功能,而CBV是class based view的意思,就是说在view中都是定义的类,使用类的方法来实现功能。

举个例子,应该也是最典型的例子。首先先建一个最基本的django框架,然后开始来做FBV和CBV的对比。

markdown 复制代码
drf_study/
├── apps/
│   └── case01/
├── drf_study/
│   ├── __pycache__/
│   ├── __init__.py
│   ├── asgi.py
│   ├── settings.py
│   ├── urls.py
│   └── wsgi.py
├── manage.py
└── requirements.txt

FBV和CBV在两个地方有区别,一个是路由上,一个是视图上。

在路上有,我先在urls上分别定一个FBV路由和CBV路由,来看一下区别。

python 复制代码
# drf_study/urls.py
from django.urls import path  
from apps.case01 import views  
  
urlpatterns = [  
    path('fbv/', views.fbv),                    # FBV路由,指向一个函数,当路由进来的时候,就执行这个函数  
    path('cbv/', views.CbvViews.as_view()),     # CBV路由,指向as_view的返回结果  
]

再来看一下视图上的区别:

python 复制代码
# drf_study/case01/views.py
from django.http import HttpResponse  
from django.views import View       # 要用CBV,一定要导入这个类,所有的CBV中的C都继承自这个类  
  
def fbv(request):  
    return HttpResponse("<h1>this is fev</h1>")  
  
  
class CbvViews(View):  
  
    # 如果是GET请求就执行下面的函数  
    def get(self, request):  
        return HttpResponse("<h1>this is CBV</h1>")

上面的两个请求还是有一些区别,在FBV中,任何请求都会返回,而在CBV中只有GET请求才会返回内容,如果是POST的请求,它不会返回,因为在CbvView这个类中没有定义POST请求的调用方法。

如果要让FBV中也达到CBV中的效果,那么需要在FBV的函数中加上一个判断才可以。

python 复制代码
# drf_study/case01/views.py
from django.http import HttpResponse  
from django.views import View       # 要用CBV,一定要导入这个类,所有的CBV中的C都继承自这个类  
  
def fbv(request):  
    if request.method == 'GET':  
        return HttpResponse("<h1>this is fev</h1>")  
    else:  
        return HttpResponse("<h1>this is not get method</h1>")
  
  
class CbvViews(View):  
  
    # 如果是GET请求就执行下面的函数  
    def get(self, request):  
        return HttpResponse("<h1>this is CBV</h1>")

那么为什么CBV的路由中返回的as_view的调用结果,就是去执行CbvViews类中定义的get函数呢?

在CBV的路由中,访问cbv/的时候,按照FBV的逻辑,在路由中对应的是一个函数引用,访问过来就去执行它。但是在CBV中它对应的是views.CbvViews.as_view(),而在视图views中写的CbvViews中并没有这个as_view()方法,所以python会去CbvViews__mro__中的下一个对象中去找,而下一个对象就是它的直接父类django中的views模块中的View类。

在django的views模块的View类中,找到了这个as_view(),这个函数返回的是as_view中定义的一个view,是一个闭包,类似于下面这个。

python 复制代码
def as_view(cls, **initkwargs):
	def view(request, *args, **kwargs):
		...
		return self.dispatch(request, *args, **kwargs)
	.....
	return view

所以在cbv/正式来的时候,就会去执行这个闭包中的view(),而这个闭包中的view()返回的是self.dispatch(request, *args, **kwargs)的结果,而这个self就是我们自己定义的CbvViews,而CbvViews我并没有定义dispatch方法,于是python又会去它的__mro__中下一个对象django中的views模块中的View类中去找。

在View中找到了这个dispatch方法,这个执行结果返回的是handler(request, *args, **kwargs)的返回结果。

python 复制代码
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_allowed  
	return handler(request, *args, **kwargs)

那么来看handler函数又是什么?handlerrequest.method.lower(),比如我们是用GET方法访问的,那么这里handler就是get,返回的handler(request, *args, **kwargs)就是get(request, *args, **kwargs),而get函数正好在我定义的CbvViews中是有的,于是就去执行CbvViews中定义的get函数了。

总结一下,所以实际上在django中不管是FBV还是CBV,路由过来了,都是去找到那个函数,并且执行它,只不过CBV在找函数的时候绕了很多的弯。

相关推荐
weixin19970108016几秒前
《二手ERP对接闲鱼API:聚石塔强制入塔后的架构重构实录》(附Python源码)
python
小白快快跑哦8 分钟前
python-字符串全解(六):正则表达式-转义与非转义
python·正则表达式·转义与非转义
IvanCodes6 小时前
Python 数据处理(十三):JSON、CSV 与数据序列化
开发语言·python
Patrick在香港7 小时前
Claude 工具调用返回空:8 次失败里只有 1 次状态码不对,其余全带 200
爬虫·python·api·claude·香港
Web3&Basketball7 小时前
CRM Agent 后训练实战:3 倍更少错误
python·架构·大模型·agent·推理
AIFQuant8 小时前
ETF行情API接入踩坑记:从报错到跑通的七个问题
python·金融·区块链·etf·基金
GPU实战笔记9 小时前
云端 Python 开发:JupyterLab 还是 VS Code Remote-SSH?
python·vs code·jupyterlab·remote-ssh·远程开发
狗狗狗狗狗乐啊10 小时前
搭一个 AI 对话工作台 AChat:从 0 到可用的完整记录(一)
python·react.js·ai编程
白猫不黑10 小时前
Python实现简易Web弱口令爆破与防护方案
python·web安全·计算机·网络安全·黑客·信息安全·渗透测试
kuuailetianzi11 小时前
Python初识:定位、优势与发展历程
python