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

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

相关推荐
前端精髓4 小时前
结构化输出with_structured_output(抽卡)
python·langchain
尹人入圣5 小时前
目前热门的IP驱动产业新场景新工具
网络·python·网络协议·tcp/ip
Nuanyt6 小时前
Agent 学习笔记(下篇三):上线工程、进阶选择与操作界面(Stage 7 / 7.5 / 8 + 延伸路线)
笔记·python·学习·memory·aiagent·harness
吴卫斌6 小时前
定投ETF实战指南(四):行业/主题ETF——定投的“进攻端“
开发语言·python·股票·量化
2601_967987376 小时前
Python——入门级(定义功能def函数)
python·函数·可变参数·默认参数·关键字参数
专注仿真8 小时前
梯度提升类(XFBoost)算法详解与代码实例
开发语言·人工智能·python·算法·大模型训练·控制算法
外收内放9 小时前
Python基础语法练习题(75)
开发语言·python·学习
黑十10 小时前
PyTorch 报 “no CUDA GPUs are available“ 怎么办?3 步排查
服务器·网络·人工智能·pytorch·python
threelab10 小时前
开源图片去水印代码
python
taller_200011 小时前
【012】数据类型入门: Excel 数据到 Python 值的转换
python·excel·pie·py