模板¶
作为一个Web框架,Django需要一种方便的方法来动态生成HTML。最常见的方法依赖于模板。模板包含所需HTML输出的静态部分,以及一些描述如何插入动态内容的特殊语法。有关使用模板创建HTML页面的实际示例,请参阅 教程3。
Django项目可以配置一个或多个模板引擎(如果不使用模板,甚至为零)。 Django为自己的模板系统内置了后端,创造性地称为Django模板语言(DTL),并为流行的替代 Jinja2。其他模板语言的后端可以从第三方获得。
Django为加载和渲染模板定义了一个标准API,而不管后端。加载包括找到给定标识符的模板并对其进行预处理,通常将其编译为内存中的表示。渲染意味着用上下文数据内插模板并返回结果字符串。
Django模板语言 是Django自己的模板系统。直到Django 1.8它是唯一的内置选项可用。这是一个很好的模板库,即使它是相当褒扬和运动几个特点。如果你没有迫切的理由选择另一个后端,你应该使用DTL,特别是如果你编写一个可插入的应用程序,并且你打算分发模板。 Django的包含模板的应用程序,如 django.contrib.admin,使用DTL。
由于历史原因,模板引擎的通用支持和Django模板语言的实现都位于 django.template
命名空间中。
支持模板引擎¶
组态¶
模板引擎使用 TEMPLATES
设置进行配置。这是一个配置列表,每个引擎一个。默认值为空。 startproject
命令生成的 settings.py
定义了一个更有用的值:
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [],
'APP_DIRS': True,
'OPTIONS': {
# ... some options here ...
},
},
]
BACKEND
是实现Django的模板后端API的模板引擎类的点分Python路径。内置后端是 django.template.backends.django.DjangoTemplates
和 django.template.backends.jinja2.Jinja2
。
由于大多数引擎从文件加载模板,每个引擎的顶级配置包含两个常见设置:
虽然不常见,但可以使用不同的选项配置同一后端的多个实例。在这种情况下,您应该为每个引擎定义唯一的 NAME
。
OPTIONS
包含后端特定的设置。
用法¶
django.template.loader
模块定义了两个加载模板的函数。
-
get_template
(template_name, using=None)[源代码]¶ 此函数加载具有给定名称的模板,并返回
Template
对象。返回值的确切类型取决于加载模板的后端。每个后端都有自己的
Template
类。get_template()
按顺序尝试每个模板引擎,直到成功。如果找不到模板,它会引发TemplateDoesNotExist
。如果找到模板但包含无效的语法,则会引发TemplateSyntaxError
。如何搜索和加载模板取决于每个引擎的后端和配置。
如果要限制搜索到特定模板引擎,请在
using
参数中传递引擎的NAME
。
-
select_template
(template_name_list, using=None)[源代码]¶ select_template()
就像get_template()
,除了它需要一个模板名称列表。它按顺序尝试每个名称并返回存在的第一个模板。
如果加载模板失败,可能会引发 django.template
中定义的以下两个异常:
-
exception
TemplateDoesNotExist
(msg, tried=None, backend=None, chain=None)[源代码]¶ 当无法找到模板时引发此异常。它接受以下可选参数,用于在调试页面上填充 模板postmortem:
backend
引发异常的模板后端实例。
tried
找到模板时尝试的源的列表。这被格式化为包含
(origin, status)
的元组的列表,其中origin
是 原产地 对象,status
是具有未找到模板的原因的字符串。chain
尝试加载模板时引发的中间
TemplateDoesNotExist
异常的列表。这由尝试从多个引擎加载给定模板的函数(例如get_template()
)使用。
New in Django 1.9:添加了
backend
,tried
和chain
参数。
由 get_template()
和 select_template()
返回的 Template
对象必须提供具有以下签名的 render()
方法:
-
Template.
render
(context=None, request=None)¶ 使用给定的上下文呈现此模板。
如果提供
context
,它必须是dict
。如果未提供,引擎将使用空上下文呈现模板。如果提供
request
,它必须是HttpRequest
。然后引擎必须在模板中提供它以及CSRF令牌。如何实现是由每个后端。
这里是一个搜索算法的例子。对于此示例,TEMPLATES
设置为:
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [
'/home/html/example.com',
'/home/html/default',
],
},
{
'BACKEND': 'django.template.backends.jinja2.Jinja2',
'DIRS': [
'/home/html/jinja2',
],
},
]
如果你调用 get_template('story_detail.html')
,这里是Django将寻找的文件,按顺序:
/home/html/example.com/story_detail.html
('django'
发动机)/home/html/default/story_detail.html
('django'
发动机)/home/html/jinja2/story_detail.html
('jinja2'
发动机)
如果你调用 select_template(['story_253_detail.html', 'story_detail.html'])
,这里是Django将寻找:
/home/html/example.com/story_253_detail.html
('django'
发动机)/home/html/default/story_253_detail.html
('django'
发动机)/home/html/jinja2/story_253_detail.html
('jinja2'
发动机)/home/html/example.com/story_detail.html
('django'
发动机)/home/html/default/story_detail.html
('django'
发动机)/home/html/jinja2/story_detail.html
('jinja2'
发动机)
当Django找到一个存在的模板时,它停止查找。
小费
您可以使用 select_template()
进行灵活的模板加载。例如,如果你写了一个新闻故事,并想要一些故事有自定义模板,使用类似 select_template(['story_%s_detail.html' % story.id, 'story_detail.html'])
。这将允许您为单个故事使用自定义模板,使用没有自定义模板的故事的备用模板。
在每个包含模板的目录内的子目录中组织模板是可能的,并且更好。约定是为每个Django应用程序创建一个子目录,根据需要在这些子目录中创建子目录。
这是为你自己的理智。将所有模板存储在单个目录的根级别中会产生混乱。
要加载子目录中的模板,只需使用斜杠即可:
get_template('news/story_detail.html')
使用与上述相同的 TEMPLATES
选项,将尝试加载以下模板:
/home/html/example.com/news/story_detail.html
('django'
发动机)/home/html/default/news/story_detail.html
('django'
发动机)/home/html/jinja2/news/story_detail.html
('jinja2'
发动机)
此外,为了减少加载和呈现模板的重复性,Django提供了一个自动化过程的快捷函数。
-
render_to_string
(template_name, context=None, request=None, using=None)[源代码]¶ render_to_string()
加载像get_template()
的模板并立即调用其render()
方法。它接受以下参数。template_name
要加载和呈现的模板的名称。如果它是模板名称的列表,Django使用
select_template()
而不是get_template()
来查找模板。context
dict
用作模板的上下文进行渲染。request
在模板的渲染过程中可用的可选
HttpRequest
。using
可选的模板引擎
NAME
。模板的搜索将仅限于该引擎。
用法示例:
from django.template.loader import render_to_string rendered = render_to_string('my_template.html', {'foo': 'bar'})
另请参阅调用 render_to_string()
的 render()
快捷方式,并将结果馈送到适合从视图返回的 HttpResponse
中。
最后,您可以直接使用配置的引擎:
内置后端¶
将 BACKEND
设置为 'django.template.backends.django.DjangoTemplates'
以配置Django模板引擎。
当 APP_DIRS
是 True
时,DjangoTemplates
引擎在已安装应用程序的 templates
子目录中查找模板。此通用名称保留用于向后兼容性。
DjangoTemplates
引擎接受以下 OPTIONS
:
'autoescape'
:一个布尔值,控制是否启用HTML自动转义。它默认为
True
。警告
如果您正在呈现非HTML模板,请将其设置为
False
!New in Django 1.10:添加了
autoescape
选项。'context_processors'
:用于在使用请求呈现模板时用于填充上下文的可调用对象的点状Python路径列表。这些可调用包含一个请求对象作为它们的参数,并返回一个要合并到上下文中的项目的dict
。它默认为空列表。
有关详细信息,请参阅
RequestContext
。'debug'
:打开/关闭模板调试模式的布尔值。如果是True
,花哨错误页面将显示模板渲染期间引发的任何异常的详细报告。此报告包含模板的相关代码段,并突出显示相应的行。它默认为
DEBUG
设置的值。'loaders'
:模板加载器类的虚拟Python路径列表。每个Loader
类都知道如何从特定源导入模板。可选地,可以使用元组而不是字符串。元组中的第一个项应该是Loader
类名,并且在初始化期间将后续项传递给Loader
。有关详细信息,请参阅 装载机类型。
'string_if_invalid'
:模板系统应用于无效(例如拼写错误)变量的输出,作为字符串。它默认为空字符串。
有关详细信息,请参阅 如何处理无效变量。
'file_charset'
:用于读取磁盘上的模板文件的字符集。它默认为
FILE_CHARSET
的值。'libraries'
:用于向模板引擎注册的模板标记模块的标签字典和点状Python路径。这可以用于添加新库或为现有库提供备用标签。例如:OPTIONS={ 'libraries': { 'myapp_tags': 'path.to.myapp.tags', 'admin.urls': 'django.contrib.admin.templatetags.admin_urls', }, }
可以通过将相应的字典键传递到
{% load %}
标记来加载库。'builtins'
:要添加到 内置 的模板标记模块的虚拟Python路径列表。例如:OPTIONS={ 'builtins': ['myapp.builtins'], }
可以在不首先调用
{% load %}
标记的情况下使用来自内置库的标记和过滤器。
添加了 libraries
和 builtins
参数。
-
class
Jinja2
¶
需要安装 Jinja2:
$ pip install Jinja2
将 BACKEND
设置为 'django.template.backends.jinja2.Jinja2'
以配置 Jinja2 引擎。
当 APP_DIRS
是 True
时,Jinja2
引擎在已安装应用程序的 jinja2
子目录中查找模板。
OPTIONS
中最重要的条目是 'environment'
。这是一个虚线的Python路径到一个callable返回一个Jinja2环境。它默认为 'jinja2.Environment'
。 Django调用该可调用项并传递其他选项作为关键字参数。此外,Django添加了不同于Jinja2的默认值几个选项:
'autoescape'
:True
'auto_reload'
:settings.DEBUG
'undefined'
:DebugUndefined if settings.DEBUG else Undefined
有意将默认配置保持为最小。如果使用请求(例如,当使用 render()
时)呈现模板时,Jinja2
后端将全局变量 request
,csrf_input
和 csrf_token
添加到上下文。除此之外,这个后端不创建一个Django风味的环境。它不知道Django上下文处理器,过滤器和标签。为了使用Django特定的API,您必须将它们配置到环境中。
例如,您可以使用此内容创建 myproject/jinja2.py
:
from __future__ import absolute_import # Python 2 only
from django.contrib.staticfiles.storage import staticfiles_storage
from django.urls import reverse
from jinja2 import Environment
def environment(**options):
env = Environment(**options)
env.globals.update({
'static': staticfiles_storage.url,
'url': reverse,
})
return env
并将 'environment'
选项设置为 'myproject.jinja2.environment'
。
然后您可以在Jinja2模板中使用以下结构:
<img src="{{ static('path/to/company-logo.png') }}" alt="Company Logo">
<a href="{{ url('admin:index') }}">Administration</a>
标签和过滤器的概念存在于Django模板语言和Jinja2中,但它们的使用方式不同。由于Jinja2支持将模板中的参数传递给可调用对象,因此许多需要Django模板中的模板标签或过滤器的功能都可以通过调用Jinja2模板中的函数来实现,如上例所示。 Jinja2的全局命名空间不再需要模板上下文处理器。 Django模板语言没有Jinja2测试的等价物。
自定义后端¶
以下是如何实现自定义模板后端,以便使用其他模板系统。模板后端是继承 django.template.backends.base.BaseEngine
的类。它必须实现 get_template()
和可选的 from_string()
。这里有一个虚构的 foobar
模板库的例子:
from django.template import TemplateDoesNotExist, TemplateSyntaxError
from django.template.backends.base import BaseEngine
from django.template.backends.utils import csrf_input_lazy, csrf_token_lazy
import foobar
class FooBar(BaseEngine):
# Name of the subdirectory containing the templates for this engine
# inside an installed application.
app_dirname = 'foobar'
def __init__(self, params):
params = params.copy()
options = params.pop('OPTIONS').copy()
super(FooBar, self).__init__(params)
self.engine = foobar.Engine(**options)
def from_string(self, template_code):
try:
return Template(self.engine.from_string(template_code))
except foobar.TemplateCompilationFailed as exc:
raise TemplateSyntaxError(exc.args)
def get_template(self, template_name):
try:
return Template(self.engine.get_template(template_name))
except foobar.TemplateNotFound as exc:
raise TemplateDoesNotExist(exc.args, backend=self)
except foobar.TemplateCompilationFailed as exc:
raise TemplateSyntaxError(exc.args)
class Template(object):
def __init__(self, template):
self.template = template
def render(self, context=None, request=None):
if context is None:
context = {}
if request is not None:
context['request'] = request
context['csrf_input'] = csrf_input_lazy(request)
context['csrf_token'] = csrf_token_lazy(request)
return self.template.render(context)
有关详细信息,请参阅 DEP 182。
定制引擎的调试集成¶
添加了非Django模板引擎的调试页面集成。
Django调试页面具有钩子,以在模板错误出现时提供详细信息。自定义模板引擎可以使用这些钩子来增强向用户显示的回溯信息。以下钩子可用:
模板postmortem¶
当 TemplateDoesNotExist
升起时,死后出现。它列出了在尝试查找给定模板时使用的模板引擎和加载器。例如,如果配置了两个Django引擎,则事后停止将显示为:

自定义引擎可以通过在提高 TemplateDoesNotExist
时传递 backend
和 tried
参数来填充事后死亡。在模板对象上使用事后预测 应指定原点 的后端。
上下文行信息¶
如果在模板解析或渲染期间发生错误,Django可以显示发生错误的行。例如:

自定义引擎可以通过在解析和呈现期间引发的异常上设置 template_debug
属性来填充此信息。此属性是具有以下值的 dict
:
'name'
:发生异常的模板的名称。'message'
:异常消息。'source_lines'
:发生异常的行前,后和行的行。这是为了上下文,所以它不应该包含超过20行左右。'line'
:发生异常的行号。'before'
:引发错误的令牌之前的错误行上的内容。'during'
:引发错误的令牌。'after'
:引发错误的令牌之后的错误行上的内容。'total'
:source_lines
中的行数。'top'
:source_lines
开始的行号。'bottom'
:source_lines
结束的行号。
给定上述模板错误,template_debug
将看起来像:
{
'name': '/path/to/template.html',
'message': "Invalid block tag: 'syntax'",
'source_lines': [
(1, 'some\n'),
(2, 'lines\n'),
(3, 'before\n'),
(4, 'Hello {% syntax error %} {{ world }}\n'),
(5, 'some\n'),
(6, 'lines\n'),
(7, 'after\n'),
(8, ''),
],
'line': 4,
'before': 'Hello ',
'during': '{% syntax error %}',
'after': ' {{ world }}\n',
'total': 9,
'bottom': 9,
'top': 1,
}
Origin API和第三方集成¶
Django模板具有通过 template.origin
属性可用的 Origin
对象。这使得调试信息能够显示在 模板postmortem 中,以及第三方库(如 Django Debug Toolbar)中。
自定义引擎可以通过创建指定以下属性的对象来提供自己的 template.origin
信息:
'name'
:模板的完整路径。'template_name'
:传递到模板加载方法的模板的相对路径。'loader_name'
:一个可选字符串,标识用于加载模板的函数或类,例如。django.template.loaders.filesystem.Loader
。
Django模板语言¶
句法¶
关于本节
这是Django模板语言的语法的概述。详情请参阅 语言语法参考。
Django模板只是一个文本文档或使用Django模板语言标记的Python字符串。一些构造由模板引擎识别和解释。主要的是变量和标签。
使用上下文呈现模板。 Rendering将变量替换为在上下文中查找的变量,并执行标签。一切都是按原样输出。
Django模板语言的语法涉及四个构造。
变量¶
变量从上下文输出值,这是一个类似于对象的对象,将键映射到值。
变量被 {{
和 }}
这样包围:
My first name is {{ first_name }}. My last name is {{ last_name }}.
使用 {'first_name': 'John', 'last_name': 'Doe'}
的上下文,此模板呈现:
My first name is John. My last name is Doe.
字典查找,属性查找和列表索引查找用点表示法实现:
{{ my_dict.key }}
{{ my_object.attribute }}
{{ my_list.0 }}
如果一个变量解析为一个可调用,模板系统将调用它没有参数,并使用其结果,而不是可调用。
标签¶
标签在呈现过程中提供任意逻辑。
这个定义是刻意含糊的。例如,标签可以输出内容,用作控制结构。 “if”语句或“for”循环,从数据库抓取内容,甚至启用对其他模板标签的访问。
标签被 {%
和 %}
这样包围:
{% csrf_token %}
大多数标签接受参数:
{% cycle 'odd' 'even' %}
有些标签需要开始和结束标签:
{% if user.is_authenticated %}Hello, {{ user.username }}.{% endif %}
内置标签的引用 可用以及 编写自定义标签的说明。
过滤器¶
过滤器转换变量和标签参数的值。
他们看起来像这样:
{{ django|title }}
使用 {'django': 'the web framework for perfectionists with deadlines'}
的上下文,此模板呈现:
The Web Framework For Perfectionists With Deadlines
一些过滤器接受参数:
{{ my_date|date:"Y-m-d" }}
内置滤波器的参考 可用以及 编写自定义过滤器的说明。
组件¶
关于本节
这是Django模板语言的API的概述。详情请参阅 API参考。
发动机¶
django.template.Engine
封装了Django模板系统的一个实例。直接实例化 Engine
的主要原因是在Django项目之外使用Django模板语言。
django.template.backends.django.DjangoTemplates
是一个薄包装器,适应 django.template.Engine
到Django模板后端API。
模板¶
django.template.Template
表示编译的模板。使用 Engine.get_template()
或 Engine.from_string()
获取模板
同样,django.template.backends.django.Template
是使 django.template.Template
适应于公共模板API的薄包装。
上下文¶
除了上下文数据之外,django.template.Context
还保存一些元数据。它被传递给 Template.render()
用于渲染模板。
django.template.RequestContext
是 Context
的子类,存储当前 HttpRequest
并运行模板上下文处理器。
通用API没有等价概念。上下文数据在普通 dict
中传递,并且如果需要,单独传递当前 HttpRequest
。
上下文处理器¶
上下文处理器是接收当前 HttpRequest
作为参数并返回要添加到呈现上下文的数据的 dict
的函数。
它们的主要用途是将所有模板共享的公共数据添加到上下文中,而不在每个视图中重复代码。
Django提供了许多 内置上下文处理器。实现自定义上下文处理器就像定义一个函数一样简单。