返回介绍

12.5 一个现代示例:Django 通用视图中的混入

发布于 2024-02-05 21:59:47 字数 3198 浏览 0 评论 0 收藏 0

 阅读本节不需要掌握 Django 知识。我只是使用这个框架的一小部分为例说明多重继承的运用,我会尽量给出所需的全部背景知识,而且假设你使用其他语言或框架做过服务器端 Web 开发。

在 Django 中,视图是可调用的对象,它的参数是表示 HTTP 请求的对象,返回值是一个表示 HTTP 响应的对象。我们要关注的是这些响应对象。响应可以是简单的重定向,没有主体内容,也可以是复杂的内容,如在线商店的目录页面,它使用 HTML 模板渲染,列出多个货品,而且有购买按钮和详情页面链接。

起初,Django 提供的是一系列函数,这叫通用视图,实现常见的用例。例如,很多网站都需要展示搜索结果,里面包含很多项目,分成多页,而且各个项目会链接到详细信息页面。在 Django 中,这种需求使用列表视图和详情视图实现,前者用于渲染搜索结果,后者用于生成各个项目的详情页面。

然而,最初的通用视图是函数,不能扩展。如果需求与列表视图相似但不完全一样,那么不得不自己从头实现。

Django 1.3 引入了基于类的视图,而且还通过基类、混入和拿来即用的具体类提供了一些通用视图类。这些基类和混入在 django.views.generic 包的 base 模块里,如图 12-4 所示。在这张图中,位于顶部的两个类,View 和 TemplateResponseMixin,负责完全不同的工作。

 在 Classy Class-Based Views 网站中可以深入研究这些类,你可以轻松地浏览各个视图类、查看它们的全部方法(继承的、覆盖的和自己添加的)、查看图表、浏览文档,以及跳转到 GitHub 中的源码

图 12-4:django.views.generic.base 模块的 UML 类图

View 是所有视图(可能是个抽象基类)的基类,提供核心功能,如 dispatch 方法。这个方法委托具体子类实现的处理方法(handler),如 get、head、post 等,处理不同的 HTTP 动词。10RedirectView 类只继承 View,可以看到,它实现了 get、head、post 等方法。

10Django 程序员知道,as_view 类方法是 View 接口最为重要的部分,不过它与这里讨论的话题无关。

View 的具体子类应该实现处理方法,但它们为什么不在 View 接口中呢?原因是:子类只需实现它们想支持的处理方法。TemplateView 只用于显示内容,因此它只实现了 get 方法。如果把 HTTP POST 请求发给 TemplateView,经继承的 View.dispatch 方法检查,它没有 post 处理方法,因此会返回 HTTP 405 Method Not Allowed(不允许使用的方法)响应。11

11如果深入了解设计模式,你会发现 Django 的分派机制是动态版模板方法模式。之所以说是动态的,是因为 View 类不强制子类实现所有处理方法,而是让 dispatch 方法在运行时检查有没有针对特定请求的具体处理方法。

TemplateResponseMixin 提供的功能只针对需要使用模板的视图。例如,RedirectView 没有主体内容,因此它不需要模板,也就没有继承这个混入。TemplateResponseMixin 为 TemplateView 和 django.views.generic 包中定义的使用模板渲染的其他视图(例如 ListView、DetailView,等等)提供行为。图 12-5 是 django.views.generic.list 模块和部分 base 模块的图解。

图 12-5:django.views.generic.list 模块的 UML 类图;图中属于 base 模块的三个类没有详细说明(参见图 12-4);ListView 类没有方法和属性,它是一个聚合类

对 Django 用户来说,在图 12-5 中,最重要的类是 ListView。这是一个聚合类,不含任何代码(定义体中只有一个文档字符串)。ListView 实例有个 object_list 属性,模板会迭代它显示页面的内容,通常是数据库查询返回的多个对象。生成这个可迭代对象列表的相关功能都由 MultipleObjectMixin 提供。这个混入还提供了复杂的分页逻辑,即在一页中显示部分结果,并提供指向其他页面的链接。

假设你想创建一个使用模板渲染的视图,但是会生成一组 JSON 格式的对象,此时用得到 BaseListView 类。这个类提供了易于使用的扩展点,把 View 和 MultipleObjectMixin 的功能整合在一起,避免了模板机制的开销。

与 Tkinter 相比,Django 基于类的视图 API 是多重继承更好的示例。尤其是,Django 的混入类易于理解:各个混入的目的明确,而且名称的后缀都是 ...Mixin。

Django 用户还没有完全拥抱基于类的视图。很多人确实在使用,但是用法有限,把它们当成黑盒;需要新功能时,很多 Django 程序员依然选择编写单块视图函数,负责处理所有事务,而不尝试重用基视图和混入。

学习基于类的视图和根据应用需求扩展它们确实需要一些时间,不过我觉得这是值得的:基于类的视图能避免大量样板代码,便于重用,还能增进团队交流——例如,为模板和传给模板上下文的变量定义标准的名称。基于类的视图把 Django 视图带到了正轨上。

我们对多重继承和混入类的讨论到此结束。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文