Django学习-类视图

Django 的视图函数(View)是一个纯粹的 Python 函数,它接收一个 request(HTTP 请求),返回一个 response(HTTP 响应)。在其内部,它主要还负责从数据库中获取数据、处理表单数据、保存数据到数据库、以及渲染指定的 HTML 模板等。我们可以把这些操作逻辑写在一个直观的 Python 函数里,但是 Django 开发者们意识到很多视图函数中的逻辑代码都是重复和通用的,因此在较早的版本中,Django 便开始引入 Class-based View(基于类的视图,这里简称类视图)。

类视图比函数视图提供了更加高层的抽象,它将上边提及的数据库操作、表单处理、模板渲染等通用操作抽取为类视图中的方法,函数的参数、状态等则抽取为类视图的属性,最终通过一个 as_view 方法将整个类视图转换为一个可调用对象(可理解为最终用于 Django URL Pattern 设置中的视图函数)。相比于书写函数视图,在 Django 中使用类视图可使得重复代码更少、代码可复用性更高、代码也更加简洁优雅,但缺点是由于比函数更加高级的抽象层次,理解其代码逻辑更加困难。即使是通读过官方文档的类视图部分,新手在使用过程中依然感到有一定障碍,无法灵活运用各种内置的类通用视图,以及在必要时通过继承的方式拓展类视图。

类视图的好处:

  • 代码可读性好
  • 类视图相对于函数视图有更高的复用性, 如果其他地方需要用到某个类视图的某个特定逻辑,直接继承该类视图即可

配置路由时,使用类视图的as_view()方法来添加

urlpatterns = [
    # 视图函数:注册
    # url(r'^register/$', views.register, name='register'),
    # 类视图:注册
    url(r'^register/$', views.RegisterView.as_view(), name='register'),
]

类视图原理

    @classonlymethod
    def as_view(cls, **initkwargs):
        """
        Main entry point for a request-response process.
        """
        ...省略代码...

        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
            # 调用dispatch方法,按照不同请求方式调用不同请求方法
            return self.dispatch(request, *args, **kwargs)

        ...省略代码...

        # 返回真正的函数视图
        return view


    def dispatch(self, request, *args, **kwargs):
        # Try to dispatch to the right method; if a method doesn't exist,
        # defer to the error handler. Also defer to the error handler if the
        # request method isn't on the approved list.
        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)

源码目录结构

Django 类视图的源码位于 django.views.generic 包中,其目录结构如下:

generic/
|—— __init__.py
|—— base.py
|—— dates.py
|—— detail.py
|—— edit.py
|—— list.py

各个模块中存放的功能代码大致如下:

  • base.py 主要存放所有类视图的基类 View ,以及一些和数据库操作无关的类视图如 TemplateViewRedirectView
  • dates.py 主要存放用于按时间归档的类视图,如 ArchiveIndexView,一些视图在博客系统中非常有用,例如获取某个日期下的全部文章列表。
  • detail.py 主要存放用于从数据库获取单条记录的类视图,例如从数据库中获取某一篇博客文章。
  • edit.py 主要包含了表单处理,创建、更新和删除数据库中的单条记录的类视图。
  • list.py 主要包含了从数据库中获取多条记录的类视图,例如从数据库中获取全部博客文章列表。

当然这仅仅是一个粗略的概述,后续的系列教程中将详细讲解各个模块中的具体类的作用。

类的继承关系与命名规律

学习 Django 类视图的一个最大障碍在于代码中类的种类繁多,而且继承关系复杂,各种基类和 Mixin,初看之下会让人眼花缭乱。但是类视图的设计者并非随心所欲,随意而为地设计各个类以及为类命名的,设计者充分采纳了一个类只负责一件事的设计理念(即单一责任原则),而且命名也是遵循一套统一的规范(或者可以叫做命名规律)。举一个例子,ListView 主要用于从数据库中获取多条记录,它的继承关系如下:

ContextMixin --> MultipleObjectMixin +
|                                    |
|                                    | --> BaseListView ----  + 
|                                    |                        |
View ------------------------------- +                        | --> ListView
                                                              |
TemplateResponseMixin --> MultipleObjectTemplateResponseMixin +

整个体系非常清晰,各个类的职责也非常明确,且类的职责从命名就可以读出。例如 ContextMixin 及其子类负责获取渲染模板所需的模板变量;MultipleObjectMixin 负责从数据库获取模型对应的多条数据;View 负责处理 HTTP 请求(如 get 请求,post 请求);TemplateResponseMixin 及其子类负责渲染模板。各个类组合在一起就构成了功能完整的 ListView

完全类似的,DetailView 也是同一套路:

ContextMixin --> SingleObjectMixin - +
|                                    |
|                                    | --> BaseDetailView --  + 
|                                    |                        |
View ------------------------------- +                        | --> DetailView
                                                              |
TemplateResponseMixin --> SingleObjectTemplateResponseMixin - +

总结起来就是一个类提供一个视图所需的功能,然后将各个类通过多继承的方式组合到一起,就提供了一个功能完整的类视图。

猜你喜欢

转载自blog.csdn.net/zhangmoyan9527/article/details/82343691