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

相关推荐
B站计算机毕业设计之家4 小时前
智慧交通项目:Python+PySide6 车辆检测系统 YOLOv8+OpenCV 自定义视频 自定义检测区域 (源码+文档)✅
大数据·python·opencv·yolo·智慧交通·交通·车流量
java1234_小锋4 小时前
TensorFlow2 Python深度学习 - 深度学习概述
python·深度学习·tensorflow·tensorflow2·python深度学习
迈火5 小时前
PuLID_ComfyUI:ComfyUI中的图像生成强化插件
开发语言·人工智能·python·深度学习·计算机视觉·stable diffusion·语音识别
浔川python社7 小时前
《网络爬虫技术规范与应用指南系列》(xc—5)完
爬虫·python
MongoVIP8 小时前
Scrapy爬虫实战:正则高效解析豆瓣电影
python·scrapy
李小白668 小时前
Python文件操作
开发语言·python
weixin_525936339 小时前
金融大数据处理与分析
hadoop·python·hdfs·金融·数据分析·spark·matplotlib
Zwb2997929 小时前
Day 30 - 错误、异常与 JSON 数据 - Python学习笔记
笔记·python·学习·json
码界筑梦坊10 小时前
206-基于深度学习的胸部CT肺癌诊断项目的设计与实现
人工智能·python·深度学习·flask·毕业设计
flashlight_hi11 小时前
LeetCode 分类刷题:74. 搜索二维矩阵
python·算法·leetcode·矩阵