作为一个Web框架,Django需要一种方便的方式来动态生成HTML。最常见的方法依赖于模板。模板包含所需HTML输出的静态部分,以及一些描述如何插入动态内容的特殊语法。有关使用模板创建HTML页面的实践示例,请参见 Tutorial 3 .
Django项目可以配置一个或多个模板引擎(如果不使用模板,甚至为零)。Django为其自己的模板系统(创造性地称为Django模板语言(DTL))以及流行的替代方案提供了内置后台 Jinja2. 其他模板语言的后台可能可以从第三方获得。您还可以编写自己的自定义后台,请参阅 Custom template backend
Django定义了一个用于加载和呈现模板的标准API,而不考虑后端。加载包括查找给定标识符的模板并对其进行预处理,通常将其编译为内存中的表示形式。呈现意味着用上下文数据插入模板并返回结果字符串。
这个 Django template language 是Django自己的模板系统。在Django 1.8之前,它是唯一可用的内置选项。它是一个很好的模板库,尽管它相当固执己见,有一些特殊之处。如果您没有迫切的理由选择另一个后端,那么应该使用DTL,特别是在编写可插拔应用程序并打算分发模板的情况下。Django的contrib应用程序,包括模板,比如 django.contrib.admin 使用DTL。
出于历史原因,模板引擎的通用支持和Django模板语言的实现都存在于 django.template
命名空间。
警告
模板系统对不受信任的模板作者不安全。例如,网站不应该允许其用户提供自己的模板,因为模板作者可以执行XSS攻击和访问可能包含敏感信息的模板变量的属性。
关于本节
这是Django模板语言语法的概述。有关详细信息,请参阅 language syntax reference .
Django模板是使用Django模板语言标记的文本文档或Python字符串。模板引擎识别和解释某些结构。主要是变量和标签。
使用上下文呈现模板。呈现将变量替换为其值,这些值在上下文中查找,并执行标记。其他一切都按原样输出。
Django模板语言的语法包含四个结构。
变量从上下文输出一个值,这是一个类似dict的对象映射键到值。
变量由 {{
和 }}
如下所示:
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 }}
如果变量解析为可调用变量,模板系统将不带参数调用它,并使用其结果而不是可调用变量。
过滤器转换变量和标记参数的值。
它们看起来是这样的:
{{ django|title }}
其上下文为 {'django': 'the web framework for perfectionists with deadlines'}
,则该模板呈现为:
The Web Framework For Perfectionists With Deadlines
某些筛选器带有参数:
{{ my_date|date:"Y-m-d" }}
A reference of built-in filters 还有 instructions for writing custom filters .
评论如下:
{# this won't be rendered #}
A {{% comment %}}
标签提供多行注释。
关于本节
这是Django模板语言的API的概述。有关详细信息,请参阅 API reference .
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
如果需要,可单独通过。
模板加载器负责定位模板、加载模板和返回模板 Template
对象。
Django提供了几个 built-in template loaders 和支架 custom template loaders .
上下文处理器是接收当前 HttpRequest
作为参数并返回 dict
要添加到呈现上下文中的数据。
它们的主要用途是将所有模板共享的公共数据添加到上下文中,而不在每个视图中重复代码。
Django提供了很多 built-in context processors ,并且您还可以实现自己的额外上下文处理器。
模板引擎配置有 TEMPLATES
设置。这是一个配置列表,每个引擎一个。默认值为空。这个 settings.py
由 startproject
命令定义了一个更有用的值:
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
.
由于大多数引擎从文件加载模板,因此每个引擎的顶级配置包含两个常见设置:
DIRS
定义引擎应按搜索顺序查找模板源文件的目录列表。
APP_DIRS
指示引擎是否应在已安装的应用程序中查找模板。每个后端都为应用程序中的子目录定义了一个常规名称,应用程序中的模板应存储在该目录中。
虽然不常见,但可以使用不同的选项配置同一后端的多个实例。在这种情况下,您应该定义一个 NAME
对于每个引擎。
OPTIONS
包含后端特定的设置。
这个 django.template.loader
模块定义两个函数来加载模板。
此函数加载具有给定名称的模板并返回 Template
对象。
返回值的确切类型取决于加载模板的后端。每个后端都有自己的 Template
类。
get_template()
依次尝试每个模板引擎,直到成功为止。如果找不到模板,它将引发 TemplateDoesNotExist
. 如果找到模板但包含无效语法,则会引发 TemplateSyntaxError
.
如何搜索和加载模板取决于每个引擎的后端和配置。
如果要将搜索限制到特定的模板引擎,请传递引擎的 NAME
在 using
参数。
select_template()
就像是 get_template()
,但需要一个模板名称列表。它按顺序尝试每个名称,并返回存在的第一个模板。
如果加载模板失败,则在中定义的以下两个异常 django.template
,可以提高:
在找不到模板时引发此异常。它接受以下可选参数来填充 template postmortem 在“调试”页上:
backend
产生异常的模板后端实例。
tried
查找模板时尝试的源列表。这被格式化为包含 (origin, status)
在哪里 origin
是一个 origin-like status
是一个字符串,说明找不到模板的原因。
chain
中间人名单 TemplateDoesNotExist
尝试加载模板时引发异常。它由函数使用,例如 get_template()
尝试从多个引擎加载给定模板。
Template
返回的对象 get_template()
和 select_template()
必须提供 render()
具有以下签名的方法:
使用给定的上下文呈现此模板。
如果 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找到存在的模板时,它将停止查找。
使用 django.template.loader.select_template()
获得更大的灵活性
你可以使用 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()
加载模板 get_template()
并调用它的 render()
方法立即。它采用以下参数。
template_name
要加载和呈现的模板的名称。如果是模板名称列表,Django使用 select_template()
而不是 get_template()
找到模板。
context
A dict
用作模板的上下文进行呈现。
request
可选的 HttpRequest
这将在模板的呈现过程中可用。
using
可选模板引擎 NAME
. 对模板的搜索将仅限于该引擎。
使用实例:
from django.template.loader import render_to_string
rendered = render_to_string("my_template.html", {"foo": "bar"})
也见 render()
调用的快捷方式 render_to_string()
并将结果输入 HttpResponse
适合从视野返回。
最后,您可以直接使用配置的引擎:
集合 BACKEND
到 'django.template.backends.django.DjangoTemplates'
配置django模板引擎。
什么时候? APP_DIRS
是 True
, DjangoTemplates
引擎在中查找模板 templates
已安装应用程序的子目录。为了向后兼容,保留了这个通用名称。
DjangoTemplates
引擎接受以下条件 OPTIONS
:
'autoescape'
:控制是否启用HTML自动转义的布尔值。
它默认为 True
.
警告
只将它设置为 False
如果要呈现非HTML模板!
'context_processors'
:指向可调用文件的点式python路径列表,用于在用请求呈现模板时填充上下文。这些可调用对象将请求对象作为其参数,并返回 dict
要合并到上下文中的项。
它默认为空列表。
见 RequestContext
更多信息。
'debug'
:打开/关闭模板调试模式的布尔值。如果是 True
,花式错误页将显示模板呈现期间引发的任何异常的详细报告。此报表包含模板的相关片段,并突出显示相应的行。
它默认为 DEBUG
设置。
'loaders'
:指向模板加载程序类的点式python路径列表。各 Loader
类知道如何从特定源导入模板。或者,可以使用元组代替字符串。元组中的第一项应该是 Loader
类名称和后续项将传递给 Loader
初始化期间。
见 装载器类型 有关详细信息。
'string_if_invalid'
:模板系统应用于无效(例如拼写错误)变量的字符串输出。
它默认为空字符串。
见 如何处理无效变量 有关详细信息。
'file_charset'
:用于读取磁盘上模板文件的字符集。
它默认为 'utf-8'
.
'libraries'
:要在模板引擎中注册的模板标记模块的标签和点式python路径的字典。这可用于添加新库或为现有库提供备用标签。例如::
OPTIONS = {
"libraries": {
"myapp_tags": "path.to.myapp.tags",
"admin.urls": "django.contrib.admin.templatetags.admin_urls",
},
}
通过将相应的字典键传递给 {{% load %}}
标签。
'builtins'
:要添加到的模板标记模块的点式python路径列表 built-ins . 例如::
OPTIONS = {
"builtins": ["myapp.builtins"],
}
可以使用内置库中的标记和筛选器,而无需首先调用 {{% load %}}
标签。
要求 Jinja2 待安装:
$ python -m pip install Jinja2
...\> py -m pip install Jinja2
集合 BACKEND
到 'django.template.backends.jinja2.Jinja2'
配置一个 Jinja2 引擎。
什么时候? APP_DIRS
是 True
, Jinja2
引擎在中查找模板 jinja2
已安装应用程序的子目录。
最重要的进入 OPTIONS
是 'environment'
. 这是一条带点的python路径,指向返回jinja2环境的可调用路径。它默认为 'jinja2.Environment'
. Django调用该可调用项并将其他选项作为关键字参数传递。此外,Django还添加了一些与Jinja2不同的默认值:
'autoescape'
: True
'auto_reload'
: settings.DEBUG
'undefined'
: DebugUndefined if settings.DEBUG else Undefined
Jinja2
引擎也接受以下条件 OPTIONS
:
'context_processors'
:指向可调用文件的点式python路径列表,用于在用请求呈现模板时填充上下文。这些可调用对象将请求对象作为其参数,并返回 dict
要合并到上下文中的项。
它默认为空列表。
不鼓励将上下文处理器与jinja2模板一起使用。
上下文处理器对于django模板很有用,因为django模板不支持使用参数调用函数。由于jinja2没有这一限制,建议将用作上下文处理器的函数放在模板可用的全局变量中,使用 jinja2.Environment
如下所述。然后可以在模板中调用该函数:
{{ function(request) }}
一些django模板上下文处理器返回一个固定值。对于jinja2模板,不需要这个间接层,因为您可以直接在 jinja2.Environment
.
为jinja2添加上下文处理器的原始用例涉及:
根据请求进行昂贵的计算。
需要每个模板中的结果。
在每个模板中多次使用结果。
除非所有这些条件都满足,否则将函数传递给模板更符合金杯2的设计。
默认配置被有意地保持在最低限度。如果模板与请求一起呈现(例如在使用 render()
) Jinja2
后端添加全局 request
, csrf_input
和 csrf_token
根据上下文。除此之外,这个后端不会创建一个django风格的环境。它不知道django过滤器和标签。为了使用特定于Django的API,必须将它们配置到环境中。
例如,您可以创建 myproject/jinja2.py
包含此内容:
from django.templatetags.static import static
from django.urls import reverse
from jinja2 import Environment
def environment(**options):
env = Environment(**options)
env.globals.update(
{
"static": static,
"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模板语言和Jinja 2中,但它们的使用方式不同。由于Jinja 2支持将参数传递给模板中的调用,因此Django模板中需要模板标签或过滤器的许多功能都可以通过调用Jinja 2模板中的函数来实现,如上面的例子所示。Jinja 2的全局命名空间消除了对模板上下文处理器的需要。Django模板语言没有相当于Jinja 2测试的功能。
7月 22, 2024