{"title":"自定义模板的后端","version":"3.1","locale":"zh-hans","docname":"howto/custom-template-backend","url":"/zh-hans/3.1/howto/custom-template-backend/","canonical":"https://djangodocs.dev/zh-hans/3.1/howto/custom-template-backend/","summary":"自定义后端 Link to this heading # 以下是如何实现一个在另一个模板系统中使用的自定义后端。一个模板后端是继承自后端基本类 django.template.backends.base.BaseEngine 。它必须实现 get_template() 和可选实现 from_string() 。以下是一个模拟…","html":"<h1>自定义模板的后端<a class=\"heading-anchor\" href=\"#custom-template-backend\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h1>\n<section id=\"custom-backends\">\n<h2>自定义后端<a class=\"heading-anchor\" href=\"#custom-backends\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>以下是如何实现一个在另一个模板系统中使用的自定义后端。一个模板后端是继承自后端基本类 <code class=\"docutils literal notranslate\"><span class=\"pre\">django.template.backends.base.BaseEngine</span></code> 。它必须实现 <code class=\"docutils literal notranslate\"><span class=\"pre\">get_template()</span></code> 和可选实现 <code class=\"docutils literal notranslate\"><span class=\"pre\">from_string()</span></code> 。以下是一个模拟 <code class=\"docutils literal notranslate\"><span class=\"pre\">foobar</span></code> 模板库的例子。</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">django.template</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">TemplateDoesNotExist</span><span class=\"p\">,</span> <span class=\"n\">TemplateSyntaxError</span>\n<span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">django.template.backends.base</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">BaseEngine</span>\n<span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">django.template.backends.utils</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">csrf_input_lazy</span><span class=\"p\">,</span> <span class=\"n\">csrf_token_lazy</span>\n\n<span class=\"kn\">import</span><span class=\"w\"> </span><span class=\"nn\">foobar</span>\n\n\n<span class=\"k\">class</span><span class=\"w\"> </span><span class=\"nc\">FooBar</span><span class=\"p\">(</span><span class=\"n\">BaseEngine</span><span class=\"p\">):</span>\n\n    <span class=\"c1\"># Name of the subdirectory containing the templates for this engine</span>\n    <span class=\"c1\"># inside an installed application.</span>\n    <span class=\"n\">app_dirname</span> <span class=\"o\">=</span> <span class=\"s1\">&#39;foobar&#39;</span>\n\n    <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"fm\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">params</span><span class=\"p\">):</span>\n        <span class=\"n\">params</span> <span class=\"o\">=</span> <span class=\"n\">params</span><span class=\"o\">.</span><span class=\"n\">copy</span><span class=\"p\">()</span>\n        <span class=\"n\">options</span> <span class=\"o\">=</span> <span class=\"n\">params</span><span class=\"o\">.</span><span class=\"n\">pop</span><span class=\"p\">(</span><span class=\"s1\">&#39;OPTIONS&#39;</span><span class=\"p\">)</span><span class=\"o\">.</span><span class=\"n\">copy</span><span class=\"p\">()</span>\n        <span class=\"nb\">super</span><span class=\"p\">()</span><span class=\"o\">.</span><span class=\"fm\">__init__</span><span class=\"p\">(</span><span class=\"n\">params</span><span class=\"p\">)</span>\n\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">engine</span> <span class=\"o\">=</span> <span class=\"n\">foobar</span><span class=\"o\">.</span><span class=\"n\">Engine</span><span class=\"p\">(</span><span class=\"o\">**</span><span class=\"n\">options</span><span class=\"p\">)</span>\n\n    <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">from_string</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">template_code</span><span class=\"p\">):</span>\n        <span class=\"k\">try</span><span class=\"p\">:</span>\n            <span class=\"k\">return</span> <span class=\"n\">Template</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">engine</span><span class=\"o\">.</span><span class=\"n\">from_string</span><span class=\"p\">(</span><span class=\"n\">template_code</span><span class=\"p\">))</span>\n        <span class=\"k\">except</span> <span class=\"n\">foobar</span><span class=\"o\">.</span><span class=\"n\">TemplateCompilationFailed</span> <span class=\"k\">as</span> <span class=\"n\">exc</span><span class=\"p\">:</span>\n            <span class=\"k\">raise</span> <span class=\"n\">TemplateSyntaxError</span><span class=\"p\">(</span><span class=\"n\">exc</span><span class=\"o\">.</span><span class=\"n\">args</span><span class=\"p\">)</span>\n\n    <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">get_template</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">template_name</span><span class=\"p\">):</span>\n        <span class=\"k\">try</span><span class=\"p\">:</span>\n            <span class=\"k\">return</span> <span class=\"n\">Template</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">engine</span><span class=\"o\">.</span><span class=\"n\">get_template</span><span class=\"p\">(</span><span class=\"n\">template_name</span><span class=\"p\">))</span>\n        <span class=\"k\">except</span> <span class=\"n\">foobar</span><span class=\"o\">.</span><span class=\"n\">TemplateNotFound</span> <span class=\"k\">as</span> <span class=\"n\">exc</span><span class=\"p\">:</span>\n            <span class=\"k\">raise</span> <span class=\"n\">TemplateDoesNotExist</span><span class=\"p\">(</span><span class=\"n\">exc</span><span class=\"o\">.</span><span class=\"n\">args</span><span class=\"p\">,</span> <span class=\"n\">backend</span><span class=\"o\">=</span><span class=\"bp\">self</span><span class=\"p\">)</span>\n        <span class=\"k\">except</span> <span class=\"n\">foobar</span><span class=\"o\">.</span><span class=\"n\">TemplateCompilationFailed</span> <span class=\"k\">as</span> <span class=\"n\">exc</span><span class=\"p\">:</span>\n            <span class=\"k\">raise</span> <span class=\"n\">TemplateSyntaxError</span><span class=\"p\">(</span><span class=\"n\">exc</span><span class=\"o\">.</span><span class=\"n\">args</span><span class=\"p\">)</span>\n\n\n<span class=\"k\">class</span><span class=\"w\"> </span><span class=\"nc\">Template</span><span class=\"p\">:</span>\n\n    <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"fm\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">template</span><span class=\"p\">):</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">template</span> <span class=\"o\">=</span> <span class=\"n\">template</span>\n\n    <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">render</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">context</span><span class=\"o\">=</span><span class=\"kc\">None</span><span class=\"p\">,</span> <span class=\"n\">request</span><span class=\"o\">=</span><span class=\"kc\">None</span><span class=\"p\">):</span>\n        <span class=\"k\">if</span> <span class=\"n\">context</span> <span class=\"ow\">is</span> <span class=\"kc\">None</span><span class=\"p\">:</span>\n            <span class=\"n\">context</span> <span class=\"o\">=</span> <span class=\"p\">{}</span>\n        <span class=\"k\">if</span> <span class=\"n\">request</span> <span class=\"ow\">is</span> <span class=\"ow\">not</span> <span class=\"kc\">None</span><span class=\"p\">:</span>\n            <span class=\"n\">context</span><span class=\"p\">[</span><span class=\"s1\">&#39;request&#39;</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">request</span>\n            <span class=\"n\">context</span><span class=\"p\">[</span><span class=\"s1\">&#39;csrf_input&#39;</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">csrf_input_lazy</span><span class=\"p\">(</span><span class=\"n\">request</span><span class=\"p\">)</span>\n            <span class=\"n\">context</span><span class=\"p\">[</span><span class=\"s1\">&#39;csrf_token&#39;</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">csrf_token_lazy</span><span class=\"p\">(</span><span class=\"n\">request</span><span class=\"p\">)</span>\n        <span class=\"k\">return</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">template</span><span class=\"o\">.</span><span class=\"n\">render</span><span class=\"p\">(</span><span class=\"n\">context</span><span class=\"p\">)</span>\n</code></pre></div>\n<p>请参阅 <a class=\"reference external\" href=\"https://github.com/django/deps/blob/main/final/0182-multiple-template-engines.rst\">DEP 182</a> 以获取更多信息。</p>\n</section>\n<section id=\"debug-integration-for-custom-engines\">\n<span id=\"template-debug-integration\"></span><h2>为自定义引擎集成调试功能<a class=\"heading-anchor\" href=\"#debug-integration-for-custom-engines\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>当模板有错误时Django调试页面会提供相应的钩子信息。自定义后端引擎能使用这些钩子来细化显示给用户的回溯信息。以下是可用的钩子：</p>\n<section id=\"template-postmortem\">\n<span id=\"id1\"></span><h3>模板剖析<a class=\"heading-anchor\" href=\"#template-postmortem\"><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/3.1/topics/templates/#django.template.TemplateDoesNotExist\" title=\"django.template.TemplateDoesNotExist\"><code class=\"xref py py-exc docutils literal notranslate\"><span class=\"pre\">TemplateDoesNotExist</span></code></a> 发生时显示剖析。它会列举出尝试查找指定模板时使用的模板引擎和加载器。举个例子，如果配置了两个Django引擎，剖析显示如下：</p>\n<img alt=\"/zh-hans/3.1/_images/postmortem.png\" src=\"/zh-hans/3.1/_images/postmortem.png\" />\n<p>当 <a class=\"reference internal\" href=\"/zh-hans/3.1/topics/templates/#django.template.TemplateDoesNotExist\" title=\"django.template.TemplateDoesNotExist\"><code class=\"xref py py-exc docutils literal notranslate\"><span class=\"pre\">TemplateDoesNotExist</span></code></a> 错误触发时自定义引擎会填写 <code class=\"docutils literal notranslate\"><span class=\"pre\">后端</span></code> 和 <code class=\"docutils literal notranslate\"><span class=\"pre\">尝试</span></code> 参数。使用剖析 :ref:` 的后端必须要指定模板对象上的一个来源 1` 。</p>\n</section>\n<section id=\"contextual-line-information\">\n<h3>上下文信息<a class=\"heading-anchor\" href=\"#contextual-line-information\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>当模板解析或渲染时发生错误，Django会显示错误所在的行。举个例子：</p>\n<img alt=\"/zh-hans/3.1/_images/template-lines.png\" src=\"/zh-hans/3.1/_images/template-lines.png\" />\n<p>在解析或渲染异常中配置了 <code class=\"docutils literal notranslate\"><span class=\"pre\">template_debug</span></code> 属性的自定义引擎会显示这条信息。这个属性是一个有以下值的类 <a class=\"reference external\" href=\"https://docs.python.org/3/library/stdtypes.html#dict\" title=\"(in Python v3.14)\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">dict</span></code></a>：</p>\n<ul class=\"simple\">\n<li><p><code class=\"docutils literal notranslate\"><span class=\"pre\">'name'</span></code> ：发生异常的模板名称</p></li>\n<li><p><code class=\"docutils literal notranslate\"><span class=\"pre\">'message'</span></code>: 异常信息。</p></li>\n<li><p><code class=\"docutils literal notranslate\"><span class=\"pre\">'source_lines'</span></code>: 异常发生的行及其前后内容。这是为了上下文，所以它不应该超过二十行。</p></li>\n<li><p><code class=\"docutils literal notranslate\"><span class=\"pre\">'line'</span></code>: 异常发生的行数。</p></li>\n<li><p><code class=\"docutils literal notranslate\"><span class=\"pre\">'before'</span></code>: 发生错误的标识符的错误行前面的内容。</p></li>\n<li><p><code class=\"docutils literal notranslate\"><span class=\"pre\">'during'</span></code>: 发生错误的标识符。</p></li>\n<li><p><code class=\"docutils literal notranslate\"><span class=\"pre\">'after'</span></code>: 发生错误的标识符的错误行后面的内容。</p></li>\n<li><p><code class=\"docutils literal notranslate\"><span class=\"pre\">'total'</span></code>: <code class=\"docutils literal notranslate\"><span class=\"pre\">source_lines</span></code> 总行数。</p></li>\n<li><p><code class=\"docutils literal notranslate\"><span class=\"pre\">'top'</span></code>: <code class=\"docutils literal notranslate\"><span class=\"pre\">source_lines</span></code> 起始行数。</p></li>\n<li><p><code class=\"docutils literal notranslate\"><span class=\"pre\">'bottom'</span></code>: <code class=\"docutils literal notranslate\"><span class=\"pre\">source_lines</span></code> 结束的行数。</p></li>\n</ul>\n<p>根据上述模板错误， <code class=\"docutils literal notranslate\"><span class=\"pre\">template_debug</span></code> 会像这样：</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"p\">{</span>\n    <span class=\"s1\">&#39;name&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;/path/to/template.html&#39;</span><span class=\"p\">,</span>\n    <span class=\"s1\">&#39;message&#39;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;Invalid block tag: &#39;syntax&#39;&quot;</span><span class=\"p\">,</span>\n    <span class=\"s1\">&#39;source_lines&#39;</span><span class=\"p\">:</span> <span class=\"p\">[</span>\n        <span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">,</span> <span class=\"s1\">&#39;some</span><span class=\"se\">\\n</span><span class=\"s1\">&#39;</span><span class=\"p\">),</span>\n        <span class=\"p\">(</span><span class=\"mi\">2</span><span class=\"p\">,</span> <span class=\"s1\">&#39;lines</span><span class=\"se\">\\n</span><span class=\"s1\">&#39;</span><span class=\"p\">),</span>\n        <span class=\"p\">(</span><span class=\"mi\">3</span><span class=\"p\">,</span> <span class=\"s1\">&#39;before</span><span class=\"se\">\\n</span><span class=\"s1\">&#39;</span><span class=\"p\">),</span>\n        <span class=\"p\">(</span><span class=\"mi\">4</span><span class=\"p\">,</span> <span class=\"s1\">&#39;Hello {</span><span class=\"si\">% s</span><span class=\"s1\">yntax error %} {{ world }}</span><span class=\"se\">\\n</span><span class=\"s1\">&#39;</span><span class=\"p\">),</span>\n        <span class=\"p\">(</span><span class=\"mi\">5</span><span class=\"p\">,</span> <span class=\"s1\">&#39;some</span><span class=\"se\">\\n</span><span class=\"s1\">&#39;</span><span class=\"p\">),</span>\n        <span class=\"p\">(</span><span class=\"mi\">6</span><span class=\"p\">,</span> <span class=\"s1\">&#39;lines</span><span class=\"se\">\\n</span><span class=\"s1\">&#39;</span><span class=\"p\">),</span>\n        <span class=\"p\">(</span><span class=\"mi\">7</span><span class=\"p\">,</span> <span class=\"s1\">&#39;after</span><span class=\"se\">\\n</span><span class=\"s1\">&#39;</span><span class=\"p\">),</span>\n        <span class=\"p\">(</span><span class=\"mi\">8</span><span class=\"p\">,</span> <span class=\"s1\">&#39;&#39;</span><span class=\"p\">),</span>\n    <span class=\"p\">],</span>\n    <span class=\"s1\">&#39;line&#39;</span><span class=\"p\">:</span> <span class=\"mi\">4</span><span class=\"p\">,</span>\n    <span class=\"s1\">&#39;before&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;Hello &#39;</span><span class=\"p\">,</span>\n    <span class=\"s1\">&#39;during&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;{</span><span class=\"si\">% s</span><span class=\"s1\">yntax error %}&#39;</span><span class=\"p\">,</span>\n    <span class=\"s1\">&#39;after&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39; {{ world }}</span><span class=\"se\">\\n</span><span class=\"s1\">&#39;</span><span class=\"p\">,</span>\n    <span class=\"s1\">&#39;total&#39;</span><span class=\"p\">:</span> <span class=\"mi\">9</span><span class=\"p\">,</span>\n    <span class=\"s1\">&#39;bottom&#39;</span><span class=\"p\">:</span> <span class=\"mi\">9</span><span class=\"p\">,</span>\n    <span class=\"s1\">&#39;top&#39;</span><span class=\"p\">:</span> <span class=\"mi\">1</span><span class=\"p\">,</span>\n<span class=\"p\">}</span>\n</code></pre></div>\n</section>\n<section id=\"origin-api-and-3rd-party-integration\">\n<span id=\"template-origin-api\"></span><h3>原始API和第3方集成<a class=\"heading-anchor\" href=\"#origin-api-and-3rd-party-integration\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>Django有一个可用  <code class=\"docutils literal notranslate\"><span class=\"pre\">template.origin</span></code> 属性的 <a class=\"reference internal\" href=\"/zh-hans/3.1/ref/templates/api/#django.template.base.Origin\" title=\"django.template.base.Origin\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">Origin</span></code></a> 基本对象类。这可以让调试信息显示在 <a href=\"#id1\"><span class=\"problematic\" id=\"id2\">:ref:`template 模板剖析上，同时支持第3方库，例如 `Django Debug Toolbar`_</span></a>。</p>\n<p>自定义引擎可以通过创建有以下特定属性的对象来提供自身的 <code class=\"docutils literal notranslate\"><span class=\"pre\">template.origin</span></code> 信息。</p>\n<ul class=\"simple\">\n<li><p><code class=\"docutils literal notranslate\"><span class=\"pre\">'name'</span></code>: 模板的完整路径。</p></li>\n<li><p><code class=\"docutils literal notranslate\"><span class=\"pre\">'template_name'</span></code>: 通过模板加载方法打开的模板的相对路径。</p></li>\n<li><p><code class=\"docutils literal notranslate\"><span class=\"pre\">'loader_name'</span></code>: 一个可选的以字符串形式指定用来加载模板的文件系统类或函数, e.g. <code class=\"docutils literal notranslate\"><span class=\"pre\">django.template.loaders.filesystem.Loader</span></code>.</p></li>\n</ul>\n</section>\n</section>","rootId":"custom-template-backend","toc":[{"title":"自定义后端","anchor":"custom-backends","children":[]},{"title":"为自定义引擎集成调试功能","anchor":"debug-integration-for-custom-engines","children":[{"title":"模板剖析","anchor":"template-postmortem","children":[]},{"title":"上下文信息","anchor":"contextual-line-information","children":[]},{"title":"原始API和第3方集成","anchor":"origin-api-and-3rd-party-integration","children":[]}]}],"breadcrumbs":[{"docname":"howto/index","title":"操作指南","url":"/zh-hans/3.1/howto/"}],"prev":{"docname":"howto/custom-lookups","title":"自定义查询器","url":"/zh-hans/3.1/howto/custom-lookups/"},"next":{"docname":"howto/custom-template-tags","title":"自定义模板标签和过滤器","url":"/zh-hans/3.1/howto/custom-template-tags/"},"formats":{"html":"/zh-hans/3.1/howto/custom-template-backend/","markdown":"/zh-hans/3.1/howto/custom-template-backend.md","json":"/zh-hans/3.1/howto/custom-template-backend.json"},"source":"https://github.com/django/django/blob/stable/3.1.x/docs/howto/custom-template-backend.txt","official":"https://docs.djangoproject.com/zh-hans/3.1/howto/custom-template-backend/","inVersions":["6.1","6.0","5.2","5.1","5.0","4.2","4.1","4.0","3.2","3.1"],"inLocales":["en","zh-hans","fr","ja","id","pt-br","ko","es","el","pl"]}