Django的设计理念和哲学
django作为一个庞大的、自带电池的、整体web开发解决方案框架,源代码多、子系统多、工具多。要将如此多的内容集成到一起,必然需要一个指导性的设计理念和哲学思维。这样才不至于显得东拼西凑、杂乱无章、接口混乱,而是整体一致、思路清晰、逻辑合理。既方便了源码开发,也方便了应用开发。
下面就介绍一下django的设计理念和哲学思维,这其中有一些是django源代码中正在遵循的,一些是使用者开发项目过程中需要遵循的:
系统性原则
松耦合
django 追求各子系统(层)的低耦合和高内聚。各层之间保持代码独立、功能独立、尽量没有交联。
例如,模板层不需要知道用户的 web 请求具体情况,模型层不需要了解模板层是如何展示数据的,视图层也不关心程序员所使用的模板系统到底是哪种和怎么使用的。通俗地说,模型层只关心数据的crud,视图层只负责业务逻辑的实现,模板层只管前端页面的渲染和展示。这三个核心层之间只有数据的传递,没有代码的交互,各自相对独立。
更少的代码
django 建议每个app的代码应该尽可能地精简,应该充分利用 python 的动态能力,比如自省机制(introspection)。
快速开发
django诞生于一个新闻编辑社,其应用环境要求快速开发和迅速迭代,所以在设计之初就追求以更快的速度实现需求的处理,你只需要编写一些新代码,或者修改一些局部代码就可以实现新的站点。
不要重复地造* (dry)
除非有特殊需求,所有官方或者生态圈内已经提供的库、工具、插件和功能,请直接拿来使用,不要自己开发。
明确优于隐式
这条原则的根本意思是:不要玩花招、炫技巧,尽可能用更普通、更明确、更直观的语法,不要使用那些晦涩难懂的语法。将你的代码写得更啰嗦、更直白、更清晰,多两行不怕,多点注释更好。
一致性
框架应在所有层级上保持一致。一致性适用于从低级(python 的编码风格)到高级(使用 django 的“经验”)的所有内容。
这条规则既有代码规范上的要求,也有开发习惯的要求,要在整个项目中保持统一的风格。代码如其人,程序员是个什么样的性子和思路,在代码里能看得清清楚楚。要保持人设的统一性,不要前面是狂野粗放的大汉,后面是裹脚布又臭又长,这样不好,让人以为代码是好多不同的人写的,没有一个统一的章法。
模型层相关
明确优于隐式
字段不应该仅仅根据字段的名称来假定某些行为。这需要对系统有太多了解,并且容易出现错误。相反,其行为应该基于关键字参数,并且在某些情况下,应该基于字段的类型。
白话说就是:不要通过字段的名称上来指定它的功能,而应该通过详细、明确地选择字段的类型,定义字段的参数来设计字段。
模型应当包含所有信息
模型中应该封装一个“对象”的各个方面,并遵循 martin fowler 的 active record 设计模式。
也就是说,对于一个模型,任何与之相关的元信息、方法、函数、属性,包括其人类可读的名称,默认排序等选项,这些所有用于理解该模型所需的信息,都应该存储在模型中,而不要将它们放到视图、url或者模板中去实现。
orm相关
提高sql效率
应该尽可能少地执行sql语句,并且应该在内部优化语句。
开发者需要显式地调用 save(),而不是由框架静默地在幕后保存数据。
api应该简洁并强大
orm的api 应该允许用尽可能少的语法,来表达丰富、达意的语句。它不应该依赖于导入其他模块或辅助对象。
每一个对象都应该能够访问所有相关的对象,和系统范围,并且这种访问应该是双向的。
支持使用原生 sql 语句
orm的api 只是一个便捷的方法,但并不是最终的全部手段,框架必须支持使用原生sql语句,这一点django做到了。
url 设计相关
松耦合
django 应用中的 url 不应该与底层 python 代码耦合。将 url 与 python 函数名联系起来是一件很糟糕且丑陋的做法。
也就是说,app中的视图到底干什么,和你的url到底写成啥样没有关系,不能将url和app捆在一起绑死了。例如,一个网站可以在 /stories/ 中放置故事,而另一个网站则可以使用 /news/来放置故事,两种不同的url其背后的app是一样的,我虽然复用了app,但我可以使用另外一套url去映射它。
无限的灵活性
url 应该尽可能灵活。任何可想到的 url 设计都应该被允许。
url应该优雅
设计漂亮的url,而不是难看的 url。
在 url 中应避免出现文件后缀名。
在 url 中不应使用 vignette 式的逗号。
最后的斜杠
从技术上而言,foo.com/bar
和 foo.com/bar/
是两条不同的 url,搜索引擎爬虫(以及某些 web 流量分析工具)会将其视为独立的两个页面。但是django 会将其转为 "标准" 的 url,让搜索引擎爬虫正确识别。详细参考 append_slash
配置。
模板系统相关
逻辑分离的解决方案
我们将模板系统看作一个工具,用于控制表现方式和表示方式相关的逻辑。模板系统不应该支持超出这个基本目标的功能。
避免冗余
大多数动态网站会使用一些网站整体通用的设计,比如通用的页眉、页脚、导航栏等等。django 模板系统遵循了这一点,可以很容易地将这些元素存储在一个地方,从而减少重复的代码。
从 html 中解耦
模板系统不应该被设计成只能输出 html。它应该同样擅长生成其他基于文本的格式,或者仅仅是纯文本。
xml不应被用于模板语言
使用 xml 引擎去解析模板会在编辑模板的过程中引入很多人为错误,并在模板处理中导致不可接受的开销。
不要指望模板系统能包打天下
django 期望模板编写者有能力直接编辑 html 文本。
更加直接的处理空格
模板系统不应该用空白符来做神奇的事情。如果模板包含空白符,系统应该在处理文本时处理空格——只是显示它。任何不在模板标签中的空白符都应该显示出来。
不要发明一种编程语言
模板系统的目标不是发明一种编程语言。它的目标是提供足够的具有编程风格的功能,比如分支和循环,这对于做出表现相关的决策是至关重要的。django 模板语言(dtl) 旨在避免高级逻辑。
django 模板系统认为模板通常是由 设计师 编写的,而不是 程序员,因此不应该假设他了解 python。
所以,我们在使用django的模板系统时会发现,这只是一个具有一般编程功能的渲染工具,不要妄图把它当作一个功能强大、语法完整的编程语言来使用。
安全与保障
开箱即用的模板系统禁止包含恶意代码,例如删除数据库记录的代码。
这也是模板系统不允许有任意python代码的另一个原因。
可扩展性
模板系统应该认识到, 高阶的模板作者可能想扩展它。
这是自定义的模板标签和过滤器背后的理念。
视图
尽量简洁
编写视图应该和编写 python 函数一样简单。开发人员不应该在函数执行时实例化一个类。
使用请求对象
视图应该能够访问一个请求对象——一个储存关于当前请求的元数据的对象。对象应该直接传递给视图函数,而不是必须从全局变量访问请求数据的视图函数。这使得通过传入“假”请求对象来测试视图变得轻松、干净和容易。
根据这条理念,django每个视图函数的第一个参数都是request,从这个request中,我们可以拿到所有用户请求相关的数据。
松耦合
视图不应该关心开发人员使用哪种模板——甚至根本不用模板系统。
get 方法和 post 方法的区别
get 和 post 是不同的;开发人员应该明确地使用其中一个或另一个。框架应该使得 get 和 post 数据很容易区分。
所以,在使用函数型视图的时候,应该明确地写明:if request.method=='get':pass
,而不要使用默认的函数执行顺序。
缓存框架相关
缓存框架 的核心目的是:
更少的代码
缓存应该尽可能快。因此,围绕缓存后端的所有框架代码都应该保持在绝对的最小值,特别是对于 get() 操作。
一致性
缓存 api 应该为不同的缓存后端提供一致的接口。
可扩展性
缓存 api 应该基于开发者的需求,在应用程序级别上是可扩展的(例如,参见 cache key transformation)。