{"title":"设计理念","version":"5.2","locale":"zh-hans","docname":"misc/design-philosophies","url":"/zh-hans/5.2/misc/design-philosophies/","canonical":"https://djangodocs.dev/zh-hans/5.2/misc/design-philosophies/","summary":"本文档解释了 Django 开发人员在开发 Django 时使用的一些基本哲学， 它的目标是解释过去并指导未来 总体 Link to this heading # 松耦合 Link to this heading # Django 栈的基本目标是 低耦合高内聚…","html":"<h1>设计理念<a class=\"heading-anchor\" href=\"#design-philosophies\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h1>\n<p>本文档解释了 Django 开发人员在开发 Django 时使用的一些基本哲学， 它的目标是解释过去并指导未来</p>\n<section id=\"overall\">\n<h2>总体<a class=\"heading-anchor\" href=\"#overall\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<section id=\"loose-coupling\">\n<span id=\"id1\"></span><h3>松耦合<a class=\"heading-anchor\" href=\"#loose-coupling\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p id=\"index-0\">Django 栈的基本目标是 <a class=\"reference external\" href=\"https://wiki.c2.com/?CouplingAndCohesion\">低耦合高内聚</a>。框架里的不同层（Layers）不应该知道对方的代码，除非它们确实需要。</p>\n<p>例如，模板系统不需要知道用户的 Web 请求，数据库层不需要了解视图层，而视图层并不关心程序员所使用的模板系统。</p>\n<p>尽管为了方便 Django 带有一个完整的堆栈，但堆栈的各个部分尽可能独立于另一个堆栈。</p>\n</section>\n<section id=\"less-code\">\n<span id=\"id2\"></span><h3>更少的代码<a class=\"heading-anchor\" href=\"#less-code\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>Django 应用的代码应该尽可能地精简，Django 应该充分利用 Python 的动态能力，比如自省机制（introspection）。</p>\n</section>\n<section id=\"quick-development\">\n<span id=\"id3\"></span><h3>快速开发<a class=\"heading-anchor\" href=\"#quick-development\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>在 21 世纪，Web 框架的核心一点是让 Web 开发中枯燥的事情处理得更加快速，Django 可以做到快速的 Web 开发。</p>\n</section>\n<section id=\"don-t-repeat-yourself-dry\">\n<span id=\"dry\"></span><h3>不要重复地造轮子 (DRY)<a class=\"heading-anchor\" href=\"#don-t-repeat-yourself-dry\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p id=\"index-1\">每个独特的概念或数据片应该存在且只存在于一个地方。避免冗余，做好标准化。</p>\n<p>合理的框架应该从尽可能少的信息中推断出尽可能多的需求。</p>\n<aside class=\"admonition admonition-seealso\">\n<p class=\"admonition-title\">See also</p>\n<p><a class=\"reference external\" href=\"https://wiki.c2.com/?DontRepeatYourself\">波特兰模式知识库中关于DRY的讨论</a></p>\n</aside>\n</section>\n<section id=\"explicit-is-better-than-implicit\">\n<span id=\"id5\"></span><h3>明确优于隐式<a class=\"heading-anchor\" href=\"#explicit-is-better-than-implicit\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>这是在 <span class=\"target\" id=\"index-6\"></span><a class=\"pep reference external\" href=\"https://peps.python.org/pep-0020/\"><strong>PEP 20</strong></a> 列出的核心 Python 原则，这意味着 Django 不应该使用太多的“魔术”。除非有一个很好的理由，否则不应该出现魔术。只有当魔术创造了巨大的便利，并且使用其他方式难以实现时，它才值得使用，而且它的实现方式并不会让试图学习如何使用该功能的开发人员感到困惑。</p>\n</section>\n<section id=\"consistency\">\n<span id=\"id6\"></span><h3>一致性<a class=\"heading-anchor\" href=\"#consistency\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>框架应在所有层级上保持一致。一致性适用于从低级（Python 的编码风格）到高级（使用 Django 的“经验”）的所有内容。</p>\n</section>\n</section>\n<section id=\"models\">\n<h2>模型<a class=\"heading-anchor\" href=\"#models\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<section id=\"id7\">\n<h3>明确优于隐式<a class=\"heading-anchor\" href=\"#id7\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>字段不应该仅仅根据字段的名称来假定某些行为。这需要对系统有太多了解，并且容易出现错误。相反，其行为应该基于关键字参数，并且在某些情况下，应该基于字段的类型。</p>\n</section>\n<section id=\"include-all-relevant-domain-logic\">\n<h3>包括所有相关领域逻辑<a class=\"heading-anchor\" href=\"#include-all-relevant-domain-logic\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>模型应该封装一个“对象”的各个方面，遵循 Martin Fowler 的 <a class=\"reference external\" href=\"https://www.martinfowler.com/eaaCatalog/activeRecord.html\">Active Record</a> 设计模式。</p>\n<p>这就是为什么在模型类中要同时定义一个模型表现的数据以及关于它的信息（包括其人类可读的名称，默认排序等选项）；所有用于理解给定模型所需的信息都应该存储在模型中。</p>\n</section>\n</section>\n<section id=\"database-api\">\n<h2>数据库API<a class=\"heading-anchor\" href=\"#database-api\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>数据库API的主要用处：</p>\n<section id=\"sql-efficiency\">\n<h3>SQL效率<a class=\"heading-anchor\" href=\"#sql-efficiency\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>应该尽可能少地执行SQL语句，并且应该在内部优化语句。</p>\n<p>这就是为什么开发者需要显式地调用 <code class=\"docutils literal notranslate\"><span class=\"pre\">save()</span></code>，而不是由框架静默地在幕后保存东西。</p>\n<p>这也是为什么 <code class=\"docutils literal notranslate\"><span class=\"pre\">select_related()</span></code> <code class=\"docutils literal notranslate\"><span class=\"pre\">QuerySet</span></code> 方法存在的原因。在查询“每个关联的对象”的常见情况下，它是一个可选的性能提升器。</p>\n</section>\n<section id=\"terse-powerful-syntax\">\n<h3>简洁, 强大的语法<a class=\"heading-anchor\" href=\"#terse-powerful-syntax\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>数据库 API 应该允许用尽可能少的语法，来表达丰富、达意的语句。它不应该依赖于导入其他模块或辅助对象。</p>\n<p>当必要时, 在幕后插入应该是自动进行的.</p>\n<p>每一个对象都应该能够访问所有相关的对象, 系统范围. 这种访问应该是双向的.</p>\n</section>\n<section id=\"option-to-drop-into-raw-sql-easily-when-needed\">\n<h3>当有必要时, 可方便地选择使用原始 SQL 语句<a class=\"heading-anchor\" href=\"#option-to-drop-into-raw-sql-easily-when-needed\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>应该认识到数据库 API 只是一个便捷的方法，但并不必须是最终的全部手段。框架应该可以很容易地编写自定义的 SQL——完整的语句，或者仅仅是自定义 <code class=\"docutils literal notranslate\"><span class=\"pre\">WHERE</span></code> 子句作为 API 调用时的自定义参数。</p>\n</section>\n</section>\n<section id=\"url-design\">\n<h2>URL 设计<a class=\"heading-anchor\" href=\"#url-design\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<section id=\"id8\">\n<h3>松耦合<a class=\"heading-anchor\" href=\"#id8\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>Django 应用中的 URL 不应该与底层 Python 代码耦合。将 URL 与 Python 函数名联系起来是一件很糟糕且丑陋的做法。</p>\n<p>按照这些方法，Django URL 系统应该允许同一应用的 URL 在不同的上下文中有所不同。例如，一个网站可以在 <code class=\"docutils literal notranslate\"><span class=\"pre\">/stories/</span></code> 中放置故事，而另一个网站则可以使用 <code class=\"docutils literal notranslate\"><span class=\"pre\">/news/</span></code>。</p>\n</section>\n<section id=\"infinite-flexibility\">\n<h3>无限的灵活性<a class=\"heading-anchor\" href=\"#infinite-flexibility\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>URL 应该尽可能灵活。任何可想到的 URL 设计都应该被允许。</p>\n</section>\n<section id=\"encourage-best-practices\">\n<h3>鼓励最佳实践<a class=\"heading-anchor\" href=\"#encourage-best-practices\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>框架可以做到让开发者简单（或更加简单）地设计出漂亮的，而不是难看的 URL。</p>\n<p>在 URL 中应避免出现文件后缀名。</p>\n<p>在 URL 中使用 Vignette 式的逗号应该受到严厉的惩罚。</p>\n</section>\n<section id=\"definitive-urls\">\n<span id=\"id9\"></span><h3>定义URL<a class=\"heading-anchor\" href=\"#definitive-urls\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p id=\"index-3\">技术上，<code class=\"docutils literal notranslate\"><span class=\"pre\">foo.com/bar</span></code> 和 <code class=\"docutils literal notranslate\"><span class=\"pre\">foo.com/bar/</span></code> 是两条不同的 URL，搜索引擎爬虫（以及某些 Web 流量分析工具）会将其视为独立的页面。Django 会将其转为 &quot;标准&quot; 的 URL，让搜索引擎爬虫正确识别。</p>\n<p>详细请参考 <a class=\"reference internal\" href=\"/zh-hans/5.2/ref/settings/#std-setting-APPEND_SLASH\"><code class=\"xref std std-setting docutils literal notranslate\"><span class=\"pre\">APPEND_SLASH</span></code></a> 配置。</p>\n</section>\n</section>\n<section id=\"template-system\">\n<h2>模板系统<a class=\"heading-anchor\" href=\"#template-system\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<section id=\"separate-logic-from-presentation\">\n<span id=\"separation-of-logic-and-presentation\"></span><h3>逻辑分离的解决方案<a class=\"heading-anchor\" href=\"#separate-logic-from-presentation\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>我们将模板系统看作一个工具，用于控制表现方式和表示方式相关的逻辑。模板系统不应该支持超出这个基本目标的功能。</p>\n</section>\n<section id=\"discourage-redundancy\">\n<h3>避免冗余<a class=\"heading-anchor\" href=\"#discourage-redundancy\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>大多数动态网站会使用一些网站整体通用的设计——一个通用的页眉、页脚、导航栏，等等。Django 模板系统应该可以很容易地将这些元素存储在一个地方，从而减少重复的代码。</p>\n<p>这是 <a class=\"reference internal\" href=\"/zh-hans/5.2/ref/templates/language/#template-inheritance\"><span class=\"std std-ref\">模板继承</span></a> 背后的理念。</p>\n</section>\n<section id=\"be-decoupled-from-html\">\n<h3>从 HTML 中解耦<a class=\"heading-anchor\" href=\"#be-decoupled-from-html\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>模板系统不应该被设计成只能输出 HTML。它应该同样擅长生成其他基于文本的格式，或者仅仅是纯文本。</p>\n</section>\n<section id=\"xml-should-not-be-used-for-template-languages\">\n<h3>XML不应被用于模板语言<a class=\"heading-anchor\" href=\"#xml-should-not-be-used-for-template-languages\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p id=\"index-4\">使用 XML 引擎去解析模板会在编辑模板的过程中引入很多人为错误，并在模板处理中导致不可接受的开销。</p>\n</section>\n<section id=\"assume-designer-competence\">\n<h3>承担设计能力<a class=\"heading-anchor\" href=\"#assume-designer-competence\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>模板系统不应该有的设计是，使得模板可以在WYSIWYG（所见即所得）编辑器中也能显示得很好，比如 Dreamweaver。因为这是一个非常严重的限制，会让模板的语法不够好。Django 期望模板编写者有能力直接编辑 HTML 文本。</p>\n</section>\n<section id=\"treat-whitespace-obviously\">\n<h3>更加直接的处理空格<a class=\"heading-anchor\" href=\"#treat-whitespace-obviously\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>模板系统不应该用空白符来做神奇的事情。如果模板包含空白符，系统应该在处理文本时处理空格——只是显示它。任何不在模板标签中的空白符都应该显示出来。</p>\n</section>\n<section id=\"don-t-invent-a-programming-language\">\n<h3>不要发明一种编程语言<a class=\"heading-anchor\" href=\"#don-t-invent-a-programming-language\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>模板系统的目标不是发明一种编程语言。它的目标是提供足够的具有编程风格的功能，比如分支和循环，这对于做出表现相关的决策是至关重要的。<a class=\"reference internal\" href=\"/zh-hans/5.2/topics/templates/#template-language-intro\"><span class=\"std std-ref\">Django 模板语言（DTL）</span></a> 旨在避免高级逻辑。</p>\n</section>\n<section id=\"safety-and-security\">\n<h3>安全与保障<a class=\"heading-anchor\" href=\"#safety-and-security\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>开箱即用的模板系统禁止包含恶意代码，例如删除数据库记录的代码。</p>\n<p>这就是模板系统不允许有任意Python代码的另一个原因。</p>\n</section>\n<section id=\"extensibility\">\n<h3>可扩展性<a class=\"heading-anchor\" href=\"#extensibility\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>模板系统应该认识到, 高阶的模板作者可能想扩展它.</p>\n<p>这是自定义的模板标签和过滤器背后的理念.</p>\n</section>\n</section>\n<section id=\"views\">\n<h2>视图<a class=\"heading-anchor\" href=\"#views\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<section id=\"simplicity\">\n<h3>简洁<a class=\"heading-anchor\" href=\"#simplicity\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>编写视图应该和编写 Python 函数一样简单。开发人员不应该在函数执行时实例化一个类。</p>\n</section>\n<section id=\"use-request-objects\">\n<h3>使用请求对象<a class=\"heading-anchor\" href=\"#use-request-objects\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>视图应该能够访问一个请求对象——一个储存关于当前请求的元数据的对象。对象应该直接传递给视图函数，而不是必须从全局变量访问请求数据的视图函数。这使得通过传入“假”请求对象来测试视图变得轻松、干净和容易。</p>\n</section>\n<section id=\"id10\">\n<h3>松耦合<a class=\"heading-anchor\" href=\"#id10\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>视图不应该关心开发人员使用哪种模板——甚至根本不用模板系统。</p>\n</section>\n<section id=\"differentiate-between-get-and-post\">\n<h3>GET 方法和 POST 方法的区别<a class=\"heading-anchor\" href=\"#differentiate-between-get-and-post\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>GET 和 POST 是不同的；开发人员应该明确地使用其中一个或另一个。框架应该使得 GET 和 POST 数据很容易区分。</p>\n</section>\n</section>\n<section id=\"cache-framework\">\n<span id=\"cache-design-philosophy\"></span><h2>缓存框架<a class=\"heading-anchor\" href=\"#cache-framework\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<p><a class=\"reference internal\" href=\"/zh-hans/5.2/topics/cache/\"><span class=\"doc\">缓存框架</span></a> 的核心目的是：</p>\n<section id=\"id11\">\n<h3>更少的代码<a class=\"heading-anchor\" href=\"#id11\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>缓存应该尽可能快。因此，围绕缓存后端的所有框架代码都应该保持在绝对的最小值，特别是对于 <code class=\"docutils literal notranslate\"><span class=\"pre\">get()</span></code> 操作。</p>\n</section>\n<section id=\"id12\">\n<h3>一致性<a class=\"heading-anchor\" href=\"#id12\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>缓存 API 应该为不同的缓存后端提供一致的接口。</p>\n</section>\n<section id=\"id13\">\n<h3>可扩展性<a class=\"heading-anchor\" href=\"#id13\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>缓存 API 应该基于开发者的需求，在应用程序级别上是可扩展的（例如，参见 <a class=\"reference internal\" href=\"/zh-hans/5.2/topics/cache/#cache-key-transformation\"><span class=\"std std-ref\">缓存键转换</span></a>）。</p>\n</section>\n</section>","rootId":"design-philosophies","toc":[{"title":"总体","anchor":"overall","children":[{"title":"松耦合","anchor":"loose-coupling","children":[]},{"title":"更少的代码","anchor":"less-code","children":[]},{"title":"快速开发","anchor":"quick-development","children":[]},{"title":"不要重复地造轮子 (DRY)","anchor":"don-t-repeat-yourself-dry","children":[]},{"title":"明确优于隐式","anchor":"explicit-is-better-than-implicit","children":[]},{"title":"一致性","anchor":"consistency","children":[]}]},{"title":"模型","anchor":"models","children":[{"title":"明确优于隐式","anchor":"id7","children":[]},{"title":"包括所有相关领域逻辑","anchor":"include-all-relevant-domain-logic","children":[]}]},{"title":"数据库API","anchor":"database-api","children":[{"title":"SQL效率","anchor":"sql-efficiency","children":[]},{"title":"简洁, 强大的语法","anchor":"terse-powerful-syntax","children":[]},{"title":"当有必要时, 可方便地选择使用原始 SQL 语句","anchor":"option-to-drop-into-raw-sql-easily-when-needed","children":[]}]},{"title":"URL 设计","anchor":"url-design","children":[{"title":"松耦合","anchor":"id8","children":[]},{"title":"无限的灵活性","anchor":"infinite-flexibility","children":[]},{"title":"鼓励最佳实践","anchor":"encourage-best-practices","children":[]},{"title":"定义URL","anchor":"definitive-urls","children":[]}]},{"title":"模板系统","anchor":"template-system","children":[{"title":"逻辑分离的解决方案","anchor":"separate-logic-from-presentation","children":[]},{"title":"避免冗余","anchor":"discourage-redundancy","children":[]},{"title":"从 HTML 中解耦","anchor":"be-decoupled-from-html","children":[]},{"title":"XML不应被用于模板语言","anchor":"xml-should-not-be-used-for-template-languages","children":[]},{"title":"承担设计能力","anchor":"assume-designer-competence","children":[]},{"title":"更加直接的处理空格","anchor":"treat-whitespace-obviously","children":[]},{"title":"不要发明一种编程语言","anchor":"don-t-invent-a-programming-language","children":[]},{"title":"安全与保障","anchor":"safety-and-security","children":[]},{"title":"可扩展性","anchor":"extensibility","children":[]}]},{"title":"视图","anchor":"views","children":[{"title":"简洁","anchor":"simplicity","children":[]},{"title":"使用请求对象","anchor":"use-request-objects","children":[]},{"title":"松耦合","anchor":"id10","children":[]},{"title":"GET 方法和 POST 方法的区别","anchor":"differentiate-between-get-and-post","children":[]}]},{"title":"缓存框架","anchor":"cache-framework","children":[{"title":"更少的代码","anchor":"id11","children":[]},{"title":"一致性","anchor":"id12","children":[]},{"title":"可扩展性","anchor":"id13","children":[]}]}],"breadcrumbs":[{"docname":"misc/index","title":"元文件和杂记","url":"/zh-hans/5.2/misc/"}],"prev":{"docname":"misc/api-stability","title":"API 的稳定性","url":"/zh-hans/5.2/misc/api-stability/"},"next":{"docname":"misc/distributions","title":"Django 的第三方发布包","url":"/zh-hans/5.2/misc/distributions/"},"formats":{"html":"/zh-hans/5.2/misc/design-philosophies/","markdown":"/zh-hans/5.2/misc/design-philosophies.md","json":"/zh-hans/5.2/misc/design-philosophies.json"},"source":"https://github.com/django/django/blob/stable/5.2.x/docs/misc/design-philosophies.txt","official":"https://docs.djangoproject.com/zh-hans/5.2/misc/design-philosophies/","inVersions":["6.1","6.0","5.2","5.1","5.0","4.2","4.1","4.0","3.2","3.1","3.0","2.2","2.1","2.0"],"inLocales":["en","sv","zh-hans","ga","fr","ja","id","it","pt-br","ko","es","el","pl"]}