专栏首页JackeyGao的博客类视图 vs. 函数视图

类视图 vs. 函数视图

类视图 vs. 函数视图

Posted December 12, 2018

#Coding

基于类的视图(CBV)和基于函数的视图(FBV)到底有什么区别? 有什么优缺点? 本篇将会去探讨。 在阅读本篇之前,请记住一点「基于类的视图不会替代基于函数的视图」.

介绍

无论是类视图还是基于函数的视图, 最终绑定到 URL Conf 的都是函数. 为什么这么说? 函数绑定到 URL 上面很显式的证明了绑定的是函数, 这一点毋庸置疑。 但类是怎么被绑定成为函数的, 我们可以看下类的as_view方法.

View.as_view()

Python

class View:
    @classonlymethod
    def as_view(cls, **initkwargs):
        """Main entry point for a request-response process."""
        for key in initkwargs:
            # Code omitted for clarity
            # ...

        def view(request, *args, **kwargs):
            self = cls(**initkwargs)
            if hasattr(self, 'get') and not hasattr(self, 'head'):
                self.head = self.get
            self.request = request
            self.args = args
            self.kwargs = kwargs
            return self.dispatch(request, *args, **kwargs)

        # Code omitted for clarity
        # ...

        return view

为了方便举例, 我简短了一些代码。 你可以到 Github 上阅读全部代码.

如上面代码所示, 当我们把视图绑定到 url conf 时使用的 as_view 挂载其实返回的是一个函数.

如果我在代码里面, 显式的调用类视图必须这样做:

Python

return MyView.as_view()(request)

为了让代码显示更加自然, 有可读性,你可以这个函数分配给一个变量.

Python

view_function = MyView.as_view()
return view_function(request)

是不是很熟悉? 这样就太像基于函数的视图了, 当然view_function其实就是函数.

as_view 方法是基于类的外部接口, 他返回一个视图函数. 调用后, 视图将请求传递给dispatch() 方法,该方法将根据请求的类型(GET, POST, PUT, etc)执行响应的方法(详情参考django/views/generic/base.py, dispatch 方法.) 这个是类的一大优点.

基于类视图例子

举例创建一个基于类的视图,分别处理不同的 HTTP Method . 如果方法为 GET 则执行 get() 方法, 如果为 POST 则执行 post() ;

views.py

Python

from django.views import View

class ContactView(View):
    def get(self, request):
        # Code block for GET request

    def post(self, request):
        # Code block for POST request

urls.py

Python

urlpatterns = [
    url(r'contact/$', views.ContactView.as_view(), name='contact'),
]

基于函数视图例子

实现上面的需求, 这次基于函数, 我们需要用 if 语句控制.

views.py

Python

def contact(request):
    if request.method == 'POST':
        # Code block for POST request
    else:
        # Code block for GET request (will also match PUT, HEAD, DELETE, etc)

urls.py

Python

urlpatterns = [
    url(r'contact/$', views.contact, name='contact'),
]

这些是两者的最显要的区别. 你也可以感受到基于类视图的优势. 下面, 将会介绍基于类的通用视图(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 的视图或功能视图, 只编写你所需的代码更更加有效.

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Django小技巧01: redirect

    redirect函数会返回一个HttpResponseRedirect类,比起HttpResponseRedirect类我更喜欢使用更简洁的redirect. ...

    用户1416054
  • Django Admin输出JSON

    Django 自带Admin后台这是Django的优势所在, 这样的话我们可以开箱即用后台功能。 有人说Django重, 可能设计就是这样, 过度的封装就是让开...

    用户1416054
  • Django小技巧19: 保护敏感信息

    互联网是一片荒地, 在互联网上部署 Web 服务的时候, 安全是首要考虑的。Django 在提供可靠和安全的API方面做的非常出色.但是前提是你要正确的使用它们...

    用户1416054
  • MySQL视图更新

    昨天在写美团2019秋招笔试题的时候遇到了关于视图是否能更新的问题,突然感觉这个问题之前复习的时候重点关注过,但是却又想不全。今天特地搜了一些资料总结一下。本文...

    lin_zone
  • IOS开发之视图和视图控制器

            视图(View), 视图控制器(ViewController)是IOS开发UI部分比较重要的东西。在学习视图这一块的东西的时候,感觉和Java ...

    lizelu
  • MySQL 视图

    ​看到这里,或许你已经对MySQL 的基本操作了如指掌,这篇文章讲解MySQL高级功能中 视图的概念及其用法。

    技能锦囊
  • AI综述专栏 | 孙仕亮:多视图机器学习综述

    在科学研究中,从方法论上来讲,都应先见森林,再见树木。当前,人工智能科技迅猛发展,万木争荣,更应系统梳理脉络。为此,我们特别精选国内外优秀的综述论文,开辟“AI...

    马上科普尚尚
  • 快速学习-视图解析

    cwl_java
  • 不看后悔 —— 视图详细介绍

    在MySQL中,视图可能是我们最常用的数据库对象之一了。那么你知道视图和表的区别吗?你知道创建及使用视图要注意哪些点吗?可能很多人对视图只是一知半解,想详细了解...

    MySQL技术
  • 快速学习Oracle-视图

    我们尝试着修改视图但是发现是视图所查询的表的字段值被修改了。所以我们一般不会去修改视图。

    cwl_java

扫码关注云+社区

领取腾讯云代金券