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

相关推荐
quikai19816 分钟前
python练习第一组
开发语言·python
谷粒.15 分钟前
测试数据管理难题的7种破解方案
运维·开发语言·网络·人工智能·python
寒山李白31 分钟前
关于Python版本与supervisor版本的兼容性
windows·python·supervisord
梨落秋霜1 小时前
Python入门篇【基础语法】
开发语言·python
ada7_1 小时前
LeetCode(python)——543.二叉树的直径
数据结构·python·算法·leetcode·职场和发展
小白学大数据1 小时前
Python 多线程爬取社交媒体品牌反馈数据
开发语言·python·媒体
HAPPY酷2 小时前
压缩文件格式实战速查表 (纯文本版)
python
祝余Eleanor2 小时前
Day 31 类的定义和方法
开发语言·人工智能·python·机器学习
背心2块钱包邮2 小时前
第6节——微积分基本定理(Fundamental Theorem of Calculus,FTC)
人工智能·python·机器学习·matplotlib
larance2 小时前
修改jupyterlab 默认路径
python