类视图 vs. 函数视图
Posted December 12, 2018
基于类的视图(CBV)和基于函数的视图(FBV)到底有什么区别? 有什么优缺点? 本篇将会去探讨。 在阅读本篇之前,请记住一点「基于类的视图不会替代基于函数的视图」.
介绍
无论是类视图还是基于函数的视图, 最终绑定到 URL Conf 的都是函数. 为什么这么说? 函数绑定到 URL 上面很显式的证明了绑定的是函数, 这一点毋庸置疑。 但类是怎么被绑定成为函数的, 我们可以看下类的as_view
方法.
View.as_view()
为了方便举例, 我简短了一些代码。 你可以到 Github 上阅读全部代码.
如上面代码所示, 当我们把视图绑定到 url conf 时使用的 as_view 挂载其实返回的是一个函数.
如果我在代码里面, 显式的调用类视图必须这样做:
为了让代码显示更加自然, 有可读性,你可以这个函数分配给一个变量.
是不是很熟悉? 这样就太像基于函数的视图了, 当然view_function其实就是函数.
as_view 方法是基于类的外部接口, 他返回一个视图函数. 调用后, 视图将请求传递给dispatch() 方法,该方法将根据请求的类型(GET, POST, PUT, etc)执行响应的方法(详情参考django/views/generic/base.py, dispatch 方法.) 这个是类的一大优点.
基于类视图例子
举例创建一个基于类的视图,分别处理不同的 HTTP Method . 如果方法为 GET 则执行 get() 方法, 如果为 POST 则执行 post() ;
views.py
urls.py
基于函数视图例子
实现上面的需求, 这次基于函数, 我们需要用 if 语句控制.
views.py
urls.py
这些是两者的最显要的区别. 你也可以感受到基于类视图的优势. 下面, 将会介绍基于类的通用视图(GV), 它又是一个不同的形式.
基于类的通用视图(GV)
Django 引入了基于类的通用视图, 来处理 web 常见的用例需求, 比如创建新对象,表单处理,列表视图,分页,归档视图等.
你可以在django.views.generic
引用它们.
你可以直接使用它们来加快开发的过程,以下是可用视图的概述:
基础视图
- View (最基本的View)
- TemplateView
- RedirectView
通用展示视图
- ListView
- DetailView
通用编辑视图
- FormView
- CreateView
- UpdateView
- DeleteView
基于日期的视图
- ArchiveIndexView
- YearArchiveView
- MonthArchiveView
- WeekArchiveView
- DayArchiveView
- TodayArchiveView
- DateDetailView
你可以在Django Doc上查看基于类的通用视图一篇阅读更多的详细信息, 还有更多的mixins.
通用视图的实现, 使用大量的 mixins. 这一点, 仁者见仁智者见智.
可以查看基于类的通用视图-扁平索引 , 来查看所有的视图的方法. 它非常实用,建议把 这个页面放到浏览器书签栏里.
各种观点
#1
观点 「使用所有的通用视图(GV)」
此观点认为,Django 提供这些通用视图就是让减少开发的效率, 为什么不用呢?
#2
观点 「仅使用django.views.generic.View, 不用GV」
此观点认为, View 就足够了, 并且 View 是真正的CBV, 而通用视图则不是真正的 CBV. View 的确没有通用视图封装那么全, 但也说明了它比通用视图灵活。 在函数视图和通用视图中间位置.
#3
观点 「除非必要, 否则避免适用视图」
一般建议是从功能视图开始,这样更容易阅读和理解。并且在你需要的地方使用 CBV。一般在哪里需要用到 CBV? 任务需要在多个视图中重用代码的地方, 这个场景下 CBV 是最好的选择。
我建议是选择第三种,正如那句话『从需求场景选择最佳的实现』 最佳的做法取决你自己, .
优点和缺点
有关 CBV 和 FBV 的优缺点, 仅供参考.
Function-Based Views
优点
- 易于构建
- 可读性佳
- 显示代码流
- 直接用装饰器
缺点
- 难以扩展及复用代码
- 通过 if 条件处理HTTP方法
Class-Based Views
优点
- 轻松扩展及复用代码
- 可以面向对象如mixins(多重继承)
- 单独的类方法处理 HTTP 方法
- 内置的基于类通用视图
缺点
- 可读性差
- 隐式代码流
- 隐式mixins及父类代码
- 装饰器的使用需要额外的导入或方法覆盖
选择哪一种都没有对错, 这一切取决于你的项目背景和需求以及对以后代码扩展性的考虑.正如我开头提到的, 基于类的视图不会取代基于函数的视图, 有些情况下基于函数视图更容易实现, 有些时候繁琐的需求变更及代码复用你选择基于类视图更好.
例如我想实现一个博客, 对首页展示博客的列表, 我只需要适用一个通用视图ListView并覆盖其 queryset 属性即可大功告成.
又假如你要实现一个复杂的请求, 如一次处理多个表单,基于函数的视图的灵活性将更好为你服务.
结论
我觉得如果是初学者在做线上项目,在不了解面向对象时适用函数式编程是个好的选择,无论是对于以后维护还是开发阶段,都能 hold 住。 但也别放弃学习 OOP, 并使用 CBV 的方式实现非重要项目练手。 对于没有面向对象经验的同学,函数式编程不会觉得代码很低级, 相反一些大佬依然坚持函数式编程。 FBV代码是显式的, CBV代码大多数都是隐式的。所以FBV 容易阅读, CBV 难于阅读。
通用视图(GV)虽然封装更加具体, 但无法处理更宽泛的情况. Django 官方的建议是: 如果你难以将自己的视图实现为通用视图(重点是generic views)的子类, 那么你直接使用基于 View 的视图或功能视图, 只编写你所需的代码更更加有效.