概述
通常情况下,Django 的视图函数(View)是一个纯粹的 Python 函数,它接收一个 request(HTTP 请求),返回一个 response(HTTP 响应)。在其内部,它主要还负责从数据库中获取数据、处理表单数据、保存数据到数据库、以及渲染指定的 HTML 模板等。我们可以把这些操作逻辑写在一个直观的 Python 函数里,但是 Django 开发者们意识到很多视图函数中的逻辑代码都是重复和通用的,因此在较早的版本中,Django 便开始引入 Class-based View(基于类的视图,这里简称类视图)。
类视图比函数视图提供了更加高层的抽象,它将上边提及的数据库操作、表单处理、模板渲染等通用操作抽取为类视图中的方法,函数的参数、状态等则抽取为类视图的属性,最终通过一个 as_view 方法将整个类视图转换为一个可调用对象(可理解为最终用于 Django URL Pattern 设置中的视图函数)。相比于书写函数视图,在 Django 中使用类视图可使得重复代码更少、代码可复用性更高、代码也更加简洁优雅,但缺点是由于比函数更加高级的抽象层次,理解其代码逻辑更加困难。即使是通读过官方文档的类视图部分,新手在使用过程中依然感到有一定障碍,无法灵活运用各种内置的类通用视图,以及在必要时通过继承的方式拓展类视图(至少对我来说,刚接触类视图时就是这种状态)。
因此,本系列教程将从源码层面解析 Django 类视图的工作原理和设计理念,一旦掌握这些,以后在项目中使用类视图就可以更加得心应手和运用自如。
源码目录结构
Django 类视图的源码位于 django.views.generic 包中,其目录结构如下:
generic/
|—— __init__.py
|—— base.py
|—— dates.py
|—— detail.py
|—— edit.py
|—— list.py
各个模块中存放的功能代码大致如下:
- base.py 主要存放所有类视图的基类
View
,以及一些和数据库操作无关的类视图如TemplateView
、RedirectView
。 - 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 - +
总结起来就是一个类提供一个视图所需的功能,然后将各个类通过多继承的方式组合到一起,就提供了一个功能完整的类视图。
总结
我们从一个很高的层面概览了 Django 类视图的源码结构和类继承体系,建立这样一个宏观的源码结构地图有助于接下来对源码细节的深入探索。接下来我们便要开始深入到各个模块和各个类的源码中一探类视图的究竟了。不过在此之前,如果你还没有读过 Django 关于类视图的文档的话,建议先通读一遍,代码和实例相结合,才能更加直观地理解代码的工作原理。阅读地址:Class-based views。
如果遇到问题,请通过下面的方式寻求帮助。
- 在下方评论区留言。
更多 Django 相关教程,请访问我的个人博客:追梦人物的博客。
- 30分钟全面解析-SQL事务+隔离级别+阻塞+死锁
- 【最新TensorFlow1.4.0教程03】利用Eager Execution构建和训练卷积神经网络(CNN)
- 360护心镜脚本分析及N种绕过方式
- 清北集训Day6T1(生成函数)
- 变种XSS:持久控制
- 洛谷P1291 [SHOI2002]百事世界杯之旅(期望DP)
- 新型XSS总结两则
- 设计一个有getMin功能的栈
- BZOJ4832: [Lydsy1704月赛]抵制克苏恩(期望DP)
- 基于连通性状态压缩的动态规划问题
- 常见Flash XSS攻击方式
- BZOJ2134: 单选错位(期望乱搞)
- 详解斯坦纳点及斯坦纳树及模版归纳总结
- 浅谈错排公式的推导及应用
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 【Spark Operator】核数设置Cores/Cores Limit/Cores Request,你搞清楚没有?
- 【Ceph RGW】radosgw_usage_exporter监控用户使用量
- 【Goland】#{key}=#{value},字符串被格式化了?
- Variable变量
- 案例:OGG目标端进程ABENDED处理
- Elasticsearch深分页以及排序查询问题
- 聊聊dubbo-go的HystrixFilter
- 如何将Java工程导出成可以执行的jar
- 利用JSP内置的Application对象实现的网站引用计数
- JSP导入XML不成功的一个原因
- 生产环境日志清理脚本
- fastadmin插件开发之插件目录
- EasySwoole之定时任务面板
- Gradle构建springBoot项目
- python菜鸟教程 | if elif else 判断