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在找函数的时候绕了很多的弯。

相关推荐
c8i2 小时前
python中的闭包和装饰器
python
这里有鱼汤5 小时前
小白必看:QMT里的miniQMT入门教程
后端·python
TF男孩15 小时前
ARQ:一款低成本的消息队列,实现每秒万级吞吐
后端·python·消息队列
该用户已不存在20 小时前
Mojo vs Python vs Rust: 2025年搞AI,该学哪个?
后端·python·rust
站大爷IP1 天前
Java调用Python的5种实用方案:从简单到进阶的全场景解析
python
用户8356290780511 天前
从手动编辑到代码生成:Python 助你高效创建 Word 文档
后端·python
c8i1 天前
python中类的基本结构、特殊属性于MRO理解
python
liwulin05061 天前
【ESP32-CAM】HELLO WORLD
python
Doris_20231 天前
Python条件判断语句 if、elif 、else
前端·后端·python