Django的FBV与CBV模式

FBV 是 function based views 的英文缩写,顾名思义代表的是基于函数的视图,在以前的我们编写的代码中,在 views.py 文件编写的都是这类视图函数,相信大家对这种编写视图函数的方式已经比较的熟悉。在本节我们将介绍另一种吧编写视图函数的方式,即 CBV (class based views)基于类的视图函数。

你可能会问为什么又突然介绍 CBV,刚熟悉了 FBV 的模式,那么我只能告诉你学习技术一个循序渐进的过程,CBV 的模式相比 FBV 还是略显复杂,所以只有掌握了 FBV 模式,才能够更好的理解 CBV模式。那么 这两者到底有什么不同之处呢,使用方法又有什么区别呢?下面就让我们一起来学习新知识吧。

1. CBV与FBV的区别

我们知道 Python 是一个门面向对象的编程语言。如果我们只用函数来编写视图函数,那么就会造成很多面向对象的优点无法利用起来,比如说封装、继承、多态等。这也是 Django 之所以加入了 CBV 模式的原因。它可以让开发者使用类的形式去编写 View 视图函数。对于使用 CBV 模式优势总结了如下几点:
  • CBV 将整个视图函数的逻辑拆成了下的多个函数,依靠函数调用来实现完整的逻辑;
  • 提高代码的可复用性,更加灵活,让开发者使用面向对象的技术,比如多继承、多态等;
  • 可以用不同的函数针对不同的 HTTP 方法处理,而不是通过很多 if 判断,提高代码可读性。

当然 CBV 也不是万能的,当继承关系变得很复杂,亦或是代码不是特别规整的时候,这时要去找某一个函数到底是被哪一个父类重载也是一个麻烦事。此时使用 FBV 模式就变的很方便,所以还是要理解它们两者的区别,在合适的场景选用合适的方法,不能把其中某一种模式视为唯一。总体上来说 CBV 的模式,在实际的开发工作中使用的相对较多,所以我们要掌握这种编写 view 视图函数的模式。

2. FBV与CBV实际应用

下面就让我们实际应用一下 CBV 这种基于类的视图函数,我们 FBV 与 CBV 的方式编写如下视图函数:
#使用FBV方式
def login_fbv(request):
    if request.method=="GET":
        return HttpResponse("登录成功")
    elif request.method=="POST":
        pass
#使用CBV方式
from django.views import View
class LoginView(View): #需要继承自View类
    def get(self,request):
        return HttpResponse("登录成功")
    def post(self,request):
        pass

1) as_view()方法创建类实例

首先 CBV 需要继承自 View 类所以需要使用如下方式进行导包

from django.views import View

在 FBV 模式中 Django 的 URL 将一个请求分配给可调用的函数的即 login_fbv(),那么基于类的视图函数这种方式就不再适用了,URL 无法将一个请求分发给类去处理。针对这个问题,CBV 提供了一个 as_view() 静态方法,调用这个方法就会创建一个类的实例。

2) dispatch()分发函数

通过实例自动调用 CBV 内置 dispatch() 方法,我们把 dispatch() 方法看做一个分发函数,它会根据不同的请求方法调用相应的get()或者post()来进行处理。同样 CBV 模式也需要接受一个 HttpRequest对象即 request,最终返回一个 response 。如果想了解 dispatch()函数可以通过源码进行了解,它的主要作用就是实现请求的分发。

3) 配置CBV模式的路由

其实细心的小伙伴不难发现,其实在 Django 生成的配置文件中已经告诉我们,如何使用 CVB 方式进行路由的配置。在项目文件即 BookStore\BookStore\urls.py 中注释着如何使用的提示代码,如下所示:
Function views  #基于函数的视图配置url
    1. Add an import:  from my_app import views
    2. Add a URL to urlpatterns:  path('', views.home, name='home')
Class-based views #基于类的视图配置url
    1. Add an import:  from other_app.views import Home #第一步
    2. Add a URL to urlpatterns:  path('', Home.as_view(), name='home') #第二步

现在我们在 index\urls.py 中配置路由,如下所示:

from index.views import LoginView
urlpatterns=[path('logincbv/',LoginView.as_view())]#使用as_view()方法创建类实例

3.CBV中类属性设置方法

类属性的设置方法有两种,一种可以是使用 Python 方法,即继承父类,重写其相应的属性,或者添加新的属性,第二种方式我们可以使用路由中的 as_view() 方法传递参数属性值,从而来指定类的属性。示例如下所示:
#第一种方式重写父类
class LoginView(View): #需要继承自View类
    username='xiaoli'
    def get(self,request):
        return HttpResponse("登录成功")
    def post(self,request):
        pass
class LoginViewChild(LoginView):
    #继承后重写类属性
    username = 'xiaowang'
#第二种方法也可以
urlpatterns = [
   path(r'logincbv/', LoginView.as_view(name="xiaowang"))
]
CBV 体现了 Python 面向对象这一语言特性。CBV 是通过类的方式来编写视图函数。这相比较于 function,更能利用面向对象中多态的特性,因此更容易将项目中比较通用的功能抽象出来。

CBV 的实现原理大家可以通过看 Django 的源码就进一步的理解,大概流程就是由 path 路由的 as_view() 创建一个类的实例由此关联到类视图,关联到类视图之后,通过 CBV 内部的 dispatch() 方法进行请求的分发处理,处理完成后并将 Response 返回。

推荐文章
Shell变量:Shell变量的定义、赋值和删除

变量是任何一种编程语言都必不可少的组成部分,变量用来存放各种数据。脚本语言在定义变量时通常不需要指明类型,直接赋值就可以,Shell变量也遵循这个规则。 在Bashshell中,每一个变量的值都是字

鼠标侧键有什么用?

鼠标侧键有什么用?鼠标侧键的功能如下:1,侧键默认是网页的前进和后退键,点击即可前进、后退网页。2,在打开文件路径时,可进行前进和后退的操作。3,有些带有宏编程功能的游戏鼠标,可以自定义这两个按键。众

Django QueryDict对象

前述章节我们使用到了request.GET与request.Post,在HttpRequest对象中,GET与POST属性都是一个QueryDict的实例,而在Django中,QueryDict被定义

20个常见的Git面试题(含答案)

关于Git面试的第一个问题必须是:1.Git和SVN有什么区别?GitSVN1.Git是一个分布式的版本控制工具1.SVN是集中版本控制工具2.它属于第3代版本控制工具2.它属于第2代版本控制工具3.

Maven生成站点和报告文档(cmd命令)

前面已经完成了一个项目的基本管理过程,接下来介绍生成相关文档。 生成站点信息 在《用命令提示符创建Maven项目》教程中用到的CMD窗口输入“mvnsite”命令,就会自动生成站点信息,如图1所示。

C++静态成员变量和静态成员函数详解

类的静态成员有两种:静态成员变量和静态成员函数。静态成员变量就是在定义时前面加了static关键字的成员变量;静态成员函数就是在声明时前面加了static关键字的成员函数。 下面的CRectangl

C语言指针作为参数和返回值

C语言本质上是传值调用(callbyvalue)的语言,因为函数的形参都是局部变量,它们通过传入的实参进行初始化。 C语言的优点是,只要表达式的类型适当,就可以当作实参。另一方面,缺点是在启用函数时

函数的递归调用,C语言函数递归调用完全攻略

前面讲了函数调用,那么函数到底是如何调用的?函数调用是通过栈实现的。在调用函数时,系统会将被调函数所需的程序空间安排在一个栈中。每当调用一个函数时,就在栈顶为它分配一个存储区。每当从一个函数退出时就释

预定义宏,C语言预定义的宏详解

对于预定义宏,相信大家并不陌生。为了方便处理一些有用的信息,预处理器定义了一些预处理标识符,也就是预定义宏。预定义宏的名称都是以“__”(两条下划线)开头和结尾的,如果宏名是由两个单词组成,那么中间以

PHP __construct():构造函数/方法

构造函数(constructormethod,也称为构造器)是类中的一种特殊函数,当使用new关键字实例化一个对象时,构造函数将会自动调用。 在PHP3.0和PHP4.0中,构造函数是一个与其所在类

Python生成器(send,close,throw)方法详解

《Python生成器》一节中,详细介绍了如何创建一个生成器,以及生成器的基础用法。本节将在其基础上,继续讲解和生成器有关的一些方法。 Python生成器send()方法 我们知道,通过调用next(

什么是网盘?

网盘,又称网络U盘、网络硬盘,是由互联网公司推出的在线存储服务。网盘向用户提供文件的存储、共享、访问、备份等文档管理功能。用户可以通过因特网管理、编辑网盘里的文件。网盘的实质是网盘服务提供商将其服务器

服务消费方申请Token

目前服务提供方已经开启了调用认证,这意味着如果现在直接调用接口会被拦截,所以在调用之前需要进行认证,即获取Token并将其放到请求头中与请求头一起传输才可以调用接口。 1.调用前获取Token 获取

Unity 3D导航系统(Navigation)

Unity3DNavigation(导航)是用于实现动态物体自动寻路的一种技术,它将游戏场景中复杂的结构关系简化为带有一定信息的网格,并在这些网格的基础上通过一系列相应的计算来实现自动寻路。 本节主

C++ map插入数据(STL map插入数据)详解

map容器的成员函数insert()有多个版本,它们可以在map中插入一个或多个pair对象。只能插入map中不存在的元素。下面这个代码片段展示了如何插入单个元素: std::mappeople{

C语言汉诺塔问题,用C语言实现汉诺塔

汉诺塔问题是指:一块板上有三根针A、B、C。A针上套有64个大小不等的圆盘,按照大的在下、小的在上的顺序排列,要把这64个圆盘从A针移动到C针上,每次只能移动一个圆盘,移动过程可以借助B针。但在任何时

Linux工作管理简介(通俗易懂)

工作管理指的是在单个登录终端(也就是登录的Shell界面)同时管理多个工作的行为。也就是说,我们登陆了一个终端,已经在执行一个操作,那么是否可以在不关闭当前操作的情况下执行其他操作呢? 当然可以,我

Linux命令行自动补全功能详解(实例演示)

文件名(或者目录名)是执行Linux命令中最常见的参数,例如前面介绍的cd、mkdir、cp等命令,都涉及到了文件名。然而对初学者来说,输入完整的文件名感觉很麻烦,尤其面临文件名(目录名)特别长的时候

Redis内存回收策略

Redis也会因为内存不足而产生错误,也可能因为回收过久而导致系统长期的停顿,因此掌握执行回收策略十分有必要。在Redis的配置文件中,当Redis的内存达到规定的最大值时,允许配置6种策略中的一种进