Django 模板语言:面向 Python 程序员 — Django 文档
Django 模板语言:适用于 Python 程序员
本文档从技术角度解释了 Django 模板系统——它是如何工作的以及如何扩展它。 如果您正在寻找有关语言语法的参考,请参阅 Django 模板语言 。
它假定您了解模板、上下文、变量、标签和渲染。 如果您不熟悉这些概念,请从 对 Django 模板语言 的介绍开始。
概览
在 Python 中使用模板系统是一个三步过程:
Django 项目通常依赖 高级、后端不可知 API 来执行这些步骤中的每一步,而不是模板系统的低级 API:
- 对于 :setting:`TEMPLATES` 设置中的每个 DjangoTemplates 后端,Django 实例化一个 Engine。 DjangoTemplates 包装了 Engine 并使其适应了通用模板后端 API。
- django.template.loader 模块提供了get_template() 等函数来加载模板。 他们返回一个
django.template.backends.django.Template
,它包装了实际的 django.template.Template。 - 在上一步中获得的
Template
有一个 render() 方法,该方法将上下文和可能的请求编组到 Context 并将渲染委托给底层 ]模板。
配置引擎
如果您使用 DjangoTemplates 后端,这可能不是您要查找的文档。 下面描述的 Engine
类的实例可以使用该后端的 engine
属性访问,并且下面提到的任何属性默认值都被 DjangoTemplates 传递的内容覆盖。
- class Engine(dirs=None, app_dirs=False, context_processors=None, debug=False, loaders=None, string_if_invalid=, file_charset='utf-8', libraries=None, builtins=None, autoescape=True)
实例化
Engine
时,所有参数都必须作为关键字参数传递:dirs
是引擎查找模板源文件的目录列表。 用于配置filesystem.Loader。它默认为空列表。
app_dirs
仅影响loaders
的默认值。 见下文。默认为
False
。autoescape
控制是否启用 HTML 自动转义。默认为
True
。警告
如果您要呈现非 HTML 模板,则仅将其设置为
False
!context_processors
是可调用对象的虚线 Python 路径列表,可调用对象用于在使用请求呈现模板时填充上下文。 这些可调用对象将请求对象作为其参数,并返回要合并到上下文中的项目的dict
。它默认为空列表。
有关更多信息,请参阅 RequestContext。
debug
是一个布尔值,用于打开/关闭模板调试模式。 如果是True
,模板引擎将存储额外的调试信息,可用于显示模板渲染期间引发的任何异常的详细报告。默认为
False
。loaders
是模板加载器类的列表,指定为字符串。 每个Loader
类都知道如何从特定来源导入模板。 或者,可以使用元组代替字符串。 元组中的第一项应该是Loader
类名,后续项在初始化期间传递给Loader
。它默认为包含以下内容的列表:
'django.template.loaders.filesystem.Loader'
'django.template.loaders.app_directories.Loader'
当且仅当app_dirs
是True
。
如果
debug
是False
,这些加载器被包裹在 django.template.loaders.cached.Loader 中。有关详细信息,请参阅 加载器类型 。
string_if_invalid
是输出,作为一个字符串,模板系统应该用于无效(例如 拼写错误)变量。它默认为空字符串。
有关详细信息,请参阅 如何处理无效变量 。
file_charset
是用于读取磁盘上模板文件的字符集。默认为
'utf-8'
。'libraries'
:模板标签模块的标签和虚线 Python 路径字典,用于注册到模板引擎。 这用于添加新库或为现有库提供替代标签。 例如:Engine( libraries={ 'myapp_tags': 'path.to.myapp.tags', 'admin.urls': 'django.contrib.admin.templatetags.admin_urls', }, )
可以通过将相应的字典键传递给库来加载库 :ttag:`{% 加载 %} ` 标签。
'builtins'
:要添加到 built-ins 的模板标记模块的虚线 Python 路径列表。 例如:Engine( builtins=['myapp.builtins'], )
无需首先调用内置库中的标签和过滤器即可使用 :ttag:`{% 加载 %} ` 标签。
- static Engine.get_default()
从第一个配置的 DjangoTemplates 引擎返回底层 Engine。 如果没有配置引擎,则引发 ImproperlyConfigured。
需要保留依赖于全局可用的隐式配置引擎的 API。 强烈反对任何其他用途。
- Engine.from_string(template_code)
- 编译给定的模板代码并返回一个 Template 对象。
- Engine.get_template(template_name)
- 加载具有给定名称的模板,编译它并返回一个 Template 对象。
- Engine.select_template(template_name_list)
- 与 get_template() 类似,除了它接受名称列表并返回找到的第一个模板。
加载模板
创建 Template 的推荐方法是调用 Engine 的工厂方法:get_template()、select_template() 和 [ X164X]from_string()。
在 :setting:`TEMPLATES` 设置定义了 DjangoTemplates 引擎的 Django 项目中,可以直接实例化 Template。 如果定义了多个 DjangoTemplates 引擎,将使用第一个。
- class Template
这个班级住在
django.template.Template
。 构造函数接受一个参数——原始模板代码:from django.template import Template template = Template("My name is {{ my_name }}.")
幕后花絮
当您创建 Template
对象时,系统只会解析您的原始模板代码一次。 从那时起,它在内部存储为树状结构以提高性能。
甚至解析本身也非常快。 大多数解析通过对单个简短正则表达式的单次调用发生。
渲染上下文
一旦你有一个编译的 Template 对象,你可以用它来渲染一个上下文。 您可以重复使用同一个模板,在不同的上下文中多次渲染它。
- class Context(dict_=None)
django.template.Context
的构造函数接受一个可选参数——一个将变量名映射到变量值的字典。有关详细信息,请参阅下面的 使用上下文对象 。
- Template.render(context)
使用 Context 调用 Template 对象的
render()
方法来“填充”模板:>>> from django.template import Context, Template >>> template = Template("My name is {{ my_name }}.") >>> context = Context({"my_name": "Adrian"}) >>> template.render(context) "My name is Adrian." >>> context = Context({"my_name": "Dolores"}) >>> template.render(context) "My name is Dolores."
变量和查找
变量名必须由任意字母 (AZ)、任意数字 (0-9)、下划线(但不得以下划线开头)或点组成。
点在模板渲染中具有特殊意义。 变量名中的点表示 查找 。 具体来说,当模板系统遇到变量名中的点时,它会按以下顺序尝试以下查找:
- 字典查找。 示例:
foo["bar"]
- 属性查找。 示例:
foo.bar
- 列表索引查找。 示例:
foo[bar]
请注意,像 模板:Foo.bar
这样的模板表达式中的“bar”将被解释为文字字符串,并且不使用变量“bar”的值(如果模板上下文中存在)。
模板系统使用第一种有效的查找类型。 这是短路逻辑。 这里有一些例子:
>>> from django.template import Context, Template
>>> t = Template("My name is {{ person.first_name }}.")
>>> d = {"person": {"first_name": "Joe", "last_name": "Johnson"}}
>>> t.render(Context(d))
"My name is Joe."
>>> class PersonClass: pass
>>> p = PersonClass()
>>> p.first_name = "Ron"
>>> p.last_name = "Nasty"
>>> t.render(Context({"person": p}))
"My name is Ron."
>>> t = Template("The first stooge in the list is {{ stooges.0 }}.")
>>> c = Context({"stooges": ["Larry", "Curly", "Moe"]})
>>> t.render(c)
"The first stooge in the list is Larry."
如果变量的任何部分是可调用的,模板系统将尝试调用它。 例子:
>>> class PersonClass2:
... def name(self):
... return "Samantha"
>>> t = Template("My name is {{ person.name }}.")
>>> t.render(Context({"person": PersonClass2}))
"My name is Samantha."
可调用变量比只需要直接查找的变量稍微复杂一些。 以下是一些需要牢记的事项:
如果该变量在调用时引发异常,则该异常将被传播,除非异常具有值为
True
的属性silent_variable_failure
。 如果异常 does 具有silent_variable_failure
属性,其值为True
,则该变量将呈现为引擎的string_if_invalid
配置选项的值(一个空的字符串,默认情况下)。 例子:>>> t = Template("My name is {{ person.first_name }}.") >>> class PersonClass3: ... def first_name(self): ... raise AssertionError("foo") >>> p = PersonClass3() >>> t.render(Context({"person": p})) Traceback (most recent call last): ... AssertionError: foo >>> class SilentAssertionError(Exception): ... silent_variable_failure = True >>> class PersonClass4: ... def first_name(self): ... raise SilentAssertionError >>> p = PersonClass4() >>> t.render(Context({"person": p})) "My name is ."
请注意,django.core.exceptions.ObjectDoesNotExist 是所有 Django 数据库 API
DoesNotExist
异常的基类,具有silent_variable_failure = True
。 因此,如果您将 Django 模板与 Django 模型对象一起使用,任何DoesNotExist
异常都会静默失败。一个变量只有在它没有必需的参数时才能被调用。 否则,系统将返回引擎的
string_if_invalid
选项的值。
调用某些变量时可能会产生副作用,并且允许模板系统访问它们要么是愚蠢的,要么是一个安全漏洞。
一个很好的例子是每个 Django 模型对象上的 delete() 方法。 模板系统不应该被允许做这样的事情:
I will now delete this valuable data. {{ data.delete }}
为了防止这种情况,请在可调用变量上设置
alters_data
属性。 如果设置了alters_data=True
,模板系统将不会调用变量,而是无条件地将变量替换为string_if_invalid
。 Django 模型对象上动态生成的 delete() 和 save() 方法会自动获取alters_data=True
。 例子:def sensitive_function(self): self.database_record.delete() sensitive_function.alters_data = True
有时您可能出于其他原因想要关闭此功能,并告诉模板系统无论如何都不要调用变量。 为此,请使用值
True
在可调用对象上设置do_not_call_in_templates
属性。 然后,模板系统将就好像您的变量不可调用一样(例如,允许您访问可调用对象的属性)。
如何处理无效变量
一般情况下,如果变量不存在,模板系统会插入引擎的string_if_invalid
配置选项的值,默认设置为(空字符串)。
仅当 string_if_invalid
设置为 (空字符串)时,才会应用应用于无效变量的过滤器。 如果
string_if_invalid
设置为任何其他值,变量过滤器将被忽略。
对于 if
、for
和 regroup
模板标签,此行为略有不同。 如果为这些模板标签之一提供了无效变量,则该变量将被解释为 None
。 过滤器始终应用于这些模板标签中的无效变量。
如果 string_if_invalid
包含 '%s'
,格式标记将被替换为无效变量的名称。
仅用于调试目的!
虽然 string_if_invalid
是一个有用的调试工具,但将其作为“开发默认值”打开是个坏主意。
当遇到不存在的变量时,许多模板,包括一些 Django 的模板,都依赖于模板系统的沉默。 如果您将 以外的值分配给
string_if_invalid
,您将遇到这些模板和网站的渲染问题。
一般情况下,string_if_invalid
只应在调试特定模板问题时启用,调试完成后清除。
内置变量
每个上下文都包含 True
、False
和 None
。 如您所料,这些变量解析为相应的 Python 对象。
字符串文字的限制
Django 的模板语言无法转义用于其自身语法的字符。 例如,如果您需要输出 {%
和 %}
等字符序列,则需要 :ttag:`templatetag` 标签。
如果您想在模板过滤器或标签参数中包含这些序列,则存在类似的问题。 例如,在解析块标记时,Django 的模板解析器会在 {%
之后查找第一次出现的 %}
。 这可以防止将 "%}"
用作字符串文字。 例如,以下表达式将引发 TemplateSyntaxError
:
{% include "template.html" tvar="Some string literal with %} in it." %}
{% with tvar="Some string literal with %} in it." %}{% endwith %}
可以通过在过滤器参数中使用保留序列来触发相同的问题:
{{ some.variable|default:"}}" }}
如果您需要将字符串与这些序列一起使用,请将它们存储在模板变量中或使用自定义模板标记或过滤器来解决此限制。
使用 Context 对象
大多数情况下,您将通过将完全填充的字典传递给 Context()
来实例化 Context 对象。 但是,您也可以使用标准字典语法在 Context
对象实例化后添加和删除项目:
>>> from django.template import Context
>>> c = Context({"foo": "bar"})
>>> c['foo']
'bar'
>>> del c['foo']
>>> c['foo']
Traceback (most recent call last):
...
KeyError: 'foo'
>>> c['newvariable'] = 'hello'
>>> c['newvariable']
'hello'
- Context.get(key, otherwise=None)
- 如果
key
在上下文中,则返回key
的值,否则返回otherwise
。
- Context.setdefault(key, default=None)
- 如果
key
在上下文中,则返回其值。 否则插入值为default
的key
并返回default
。
- Context.pop()
- Context.push()
- exception ContextPopException
Context
对象是一个堆栈。 也就是说,你可以push()
和pop()
它。 如果你 pop()
太多,它会提高 django.template.ContextPopException
:
>>> c = Context()
>>> c['foo'] = 'first level'
>>> c.push()
{}
>>> c['foo'] = 'second level'
>>> c['foo']
'second level'
>>> c.pop()
{'foo': 'second level'}
>>> c['foo']
'first level'
>>> c['foo'] = 'overwritten'
>>> c['foo']
'overwritten'
>>> c.pop()
Traceback (most recent call last):
...
ContextPopException
您还可以使用 push()
作为上下文管理器来确保调用匹配的 pop()
。
>>> c = Context()
>>> c['foo'] = 'first level'
>>> with c.push():
... c['foo'] = 'second level'
... c['foo']
'second level'
>>> c['foo']
'first level'
传递给 push()
的所有参数都将传递给用于构建新上下文级别的 dict
构造函数。
>>> c = Context()
>>> c['foo'] = 'first level'
>>> with c.push(foo='second level'):
... c['foo']
'second level'
>>> c['foo']
'first level'
- Context.update(other_dict)
除了 push()
和 pop()
,Context
对象还定义了一个 update()
方法。 这与 push()
类似,但将字典作为参数并将该字典推入堆栈而不是空的。
>>> c = Context()
>>> c['foo'] = 'first level'
>>> c.update({'foo': 'updated'})
{'foo': 'updated'}
>>> c['foo']
'updated'
>>> c.pop()
{'foo': 'updated'}
>>> c['foo']
'first level'
与 push()
一样,您可以使用 update()
作为上下文管理器来确保调用匹配的 pop()
。
>>> c = Context()
>>> c['foo'] = 'first level'
>>> with c.update({'foo': 'second level'}):
... c['foo']
'second level'
>>> c['foo']
'first level'
使用 Context
作为堆栈在 一些自定义模板标签 中会派上用场。
- Context.flatten()
使用 flatten()
方法,您可以将整个 Context
堆栈作为一个字典,包括内置变量。
>>> c = Context()
>>> c['foo'] = 'first level'
>>> c.update({'bar': 'second level'})
{'bar': 'second level'}
>>> c.flatten()
{'True': True, 'None': None, 'foo': 'first level', 'False': False, 'bar': 'second level'}
flatten()
方法也在内部用于使 Context
对象具有可比性。
>>> c1 = Context()
>>> c1['foo'] = 'first level'
>>> c1['bar'] = 'second level'
>>> c2 = Context()
>>> c2.update({'bar': 'second level', 'foo': 'first level'})
{'foo': 'first level', 'bar': 'second level'}
>>> c1 == c2
True
flatten()
的结果可用于单元测试以比较 Context
与 dict
:
class ContextTest(unittest.TestCase):
def test_against_dictionary(self):
c1 = Context()
c1['update'] = 'value'
self.assertEqual(c1.flatten(), {
'True': True,
'None': None,
'False': False,
'update': 'value',
})
使用 RequestContext
- class RequestContext(request, dict_=None, processors=None)
Django 带有一个特殊的 Context
类,django.template.RequestContext
,它的作用与普通的 django.template.Context
略有不同。 第一个区别是它以 HttpRequest 作为第一个参数。 例如:
c = RequestContext(request, {
'foo': 'bar',
})
第二个区别是它根据引擎的 context_processors
配置选项自动用一些变量填充上下文。
context_processors
选项是一个可调用列表 - 称为 上下文处理器 - 将请求对象作为参数并返回要合并到上下文中的项目字典。 在默认生成的设置文件中,默认模板引擎包含以下上下文处理器:
[
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
]
除此之外,RequestContext 始终启用 'django.template.context_processors.csrf'
。 这是管理员和其他 contrib 应用程序所需的安全相关上下文处理器,并且在意外配置错误的情况下,它是故意硬编码的,无法在 context_processors
选项中关闭。
每个处理器按顺序应用。 这意味着,如果一个处理器向上下文添加一个变量,而第二个处理器添加一个同名的变量,则第二个将覆盖第一个。 默认处理器解释如下。
应用上下文处理器时
上下文处理器应用于上下文数据之上。 这意味着上下文处理器可能会覆盖您提供给 Context 或 RequestContext 的变量,因此请注意避免变量名称与上下文处理器提供的变量名称重叠。
如果您希望上下文数据优先于上下文处理器,请使用以下模式:
from django.template import RequestContext
request_context = RequestContext(request)
request_context.push({"my_name": "Adrian"})
Django 这样做是为了允许上下文数据覆盖 API 中的上下文处理器,例如 render() 和 TemplateResponse。
此外,您可以使用可选的第三个位置参数 processors
为 RequestContext 提供附加处理器列表。 在这个例子中, RequestContext 实例得到一个 ip_address
变量:
from django.http import HttpResponse
from django.template import RequestContext, Template
def ip_address_processor(request):
return {'ip_address': request.META['REMOTE_ADDR']}
def client_ip_view(request):
template = Template('{{ title }}: {{ ip_address }}')
context = RequestContext(request, {
'title': 'Your IP Address',
}, [ip_address_processor])
return HttpResponse(template.render(context))
内置模板上下文处理器
以下是每个内置处理器的作用:
django.contrib.auth.context_processors.auth
- auth()
如果启用此处理器,则每个 RequestContext
将包含以下变量:
user
– 代表当前登录用户的auth.User
实例(或AnonymousUser
实例,如果客户端未登录)。perms
–django.contrib.auth.context_processors.PermWrapper
的一个实例,代表当前登录用户拥有的权限。
django.template.context_processors.debug
- debug()
如果启用此处理器,则每个 RequestContext
将包含这两个变量 - 但前提是您的 :setting:`DEBUG` 设置设置为 True
和请求的 IP 地址(request.META['REMOTE_ADDR']
) 在 :setting:`INTERNAL_IPS` 设置中:
debug
–True
。 您可以在模板中使用它来测试您是否处于 :setting:`DEBUG` 模式。sql_queries
–{'sql': ..., 'time': ...}
字典的列表,表示到目前为止在请求期间发生的每个 SQL 查询以及花费了多长时间。 该列表按数据库别名排序,然后按查询排序。 它是在访问时惰性生成的。
django.template.context_processors.i18n
- i18n()
如果启用此处理器,则每个 RequestContext
将包含以下变量:
LANGUAGES
– :setting:`LANGUAGES` 设置的值。LANGUAGE_BIDI
–True
如果当前语言是从右到左的语言,例如 希伯来语、阿拉伯语。False
如果是从左到右的语言,例如 英语、法语、德语。LANGUAGE_CODE
–request.LANGUAGE_CODE
(如果存在)。 否则,:setting:`LANGUAGE_CODE` 设置的值。
有关生成相同值的模板标签,请参阅 i18n 模板标签 。
django.template.context_processors.media
如果启用此处理器,则每个 RequestContext
将包含一个变量 MEDIA_URL
,提供 :setting:`MEDIA_URL` 设置的值。
django.template.context_processors.static
- static()
如果启用此处理器,则每个 RequestContext
将包含一个变量 STATIC_URL
,提供 :setting:`STATIC_URL` 设置的值。
django.template.context_processors.request
如果启用该处理器,则每个 RequestContext
将包含一个变量 request
,即当前的 HttpRequest。
django.template.context_processors.tz
- tz()
如果启用此处理器,每个 RequestContext
将包含一个变量 TIME_ZONE
,提供当前活动时区的名称。
编写自己的上下文处理器
上下文处理器有一个简单的接口:它是一个 Python 函数,它接受一个参数,一个 HttpRequest 对象,并返回一个被添加到模板上下文的字典。
例如,要将 :setting:`DEFAULT_FROM_EMAIL` 设置添加到每个上下文:
from django.conf import settings
def from_email(request):
return {
"DEFAULT_FROM_EMAIL": settings.DEFAULT_FROM_EMAIL,
}
自定义上下文处理器可以存在于您的代码库中的任何位置。 所有 Django 关心的是,您的自定义上下文处理器由 :setting:`TEMPLATES` 设置中的 'context_processors'
选项或 的 context_processors
参数指向]Engine 如果你直接使用它。
加载模板
通常,您会将模板存储在文件系统上的文件中,而不是自己使用低级 Template API。 将模板保存在指定为 模板目录 的目录中。
Django 会在许多地方搜索模板目录,具体取决于您的模板加载设置(请参阅下面的“加载器类型”),但指定模板目录的最基本方法是使用 :setting:`目录 ` 选项。
这 :setting:`目录 ` 选项
告诉 Django 你的模板目录是什么 :setting:`目录 ` 选项中 :设置:`模板` 设置文件中的设置 - 或dirs
的论证引擎 . 这应该设置为包含模板目录完整路径的字符串列表:
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [
'/home/html/templates/lawrence.com',
'/home/html/templates/default',
],
},
]
只要目录和模板可由 Web 服务器读取,您的模板就可以放在您想要的任何位置。 它们可以有您想要的任何扩展名,例如 .html
或 .txt
,也可以根本没有扩展名。
请注意,即使在 Windows 上,这些路径也应使用 Unix 样式的正斜杠。
装载机类型
默认情况下,Django 使用基于文件系统的模板加载器,但 Django 附带了一些其他模板加载器,它们知道如何从其他来源加载模板。
这些其他加载器中的一些默认情况下是禁用的,但您可以通过在 :setting:`TEMPLATES` 设置或 DjangoTemplates
后端添加 'loaders'
选项来激活它们将 loaders
参数传递给 Engine。 loaders
应该是一个字符串或元组的列表,其中每个代表一个模板加载器类。 以下是 Django 附带的模板加载器:
django.template.loaders.filesystem.Loader
- class filesystem.Loader
从文件系统加载模板,根据 :setting:`目录 ` .
默认情况下启用此加载程序。 但是,在您设置之前它不会找到任何模板 :setting:`目录 ` 到非空列表:
TEMPLATES = [{ 'BACKEND': 'django.template.backends.django.DjangoTemplates', 'DIRS': [BASE_DIR / 'templates'], }]
您还可以覆盖
'DIRS'
并为特定文件系统加载器指定特定目录:TEMPLATES = [{ 'BACKEND': 'django.template.backends.django.DjangoTemplates', 'OPTIONS': { 'loaders': [ ( 'django.template.loaders.filesystem.Loader', [BASE_DIR / 'templates'], ), ], }, }]
django.template.loaders.app_directories.Loader
- class app_directories.Loader
从文件系统上的 Django 应用程序加载模板。 对于 :setting:`INSTALLED_APPS` 中的每个应用程序,加载程序查找
templates
子目录。 如果目录存在,Django 会在那里寻找模板。这意味着您可以将模板与您的个人应用程序一起存储。 这也有助于使用默认模板分发 Django 应用程序。
例如,对于此设置:
INSTALLED_APPS = ['myproject.polls', 'myproject.music']
...然后
get_template('foo.html')
将在这些目录中查找foo.html
,按以下顺序:/path/to/myproject/polls/templates/
/path/to/myproject/music/templates/
......并且将使用它首先找到的那个。
:setting:`INSTALLED_APPS` 的顺序很重要! 例如,如果您想自定义 Django 管理员,您可以选择覆盖标准的
admin/base_site.html
模板,来自django.contrib.admin
,在myproject.polls
中使用您自己的admin/base_site.html
]。 然后你必须确保你的myproject.polls
在django.contrib.admin
之前出现 在 :setting:`INSTALLED_APPS`,否则django.contrib.admin
将首先加载,您的将被忽略。请注意,加载器在首次运行时会执行优化:它缓存一个列表,其中 :setting:`INSTALLED_APPS` 包具有
templates
子目录。您可以通过设置启用此加载程序 :设置:`APP_DIRS ` 到
True
:TEMPLATES = [{ 'BACKEND': 'django.template.backends.django.DjangoTemplates', 'APP_DIRS': True, }]
django.template.loaders.cached.Loader
- class cached.Loader
默认情况下(当 :setting:`DEBUG` 为
True
时),模板系统会在每次渲染时读取和编译模板。 虽然 Django 模板系统非常快,但读取和编译模板的开销可能会增加。您可以使用它应该包装的其他加载器列表来配置缓存模板加载器。 包装的加载器用于在第一次遇到未知模板时定位它们。 缓存加载器然后将编译后的
Template
存储在内存中。 缓存的Template
实例被返回用于后续加载相同模板的请求。如果出现以下情况,将自动启用此加载程序 :设置:`选项['装载机'] ` 未指定并且 :设置:`选项['调试'] ` 是
False
(后一个选项默认为 :设置:`调试` )。您还可以使用以下设置通过一些自定义模板加载器启用模板缓存:
TEMPLATES = [{ 'BACKEND': 'django.template.backends.django.DjangoTemplates', 'DIRS': [BASE_DIR / 'templates'], 'OPTIONS': { 'loaders': [ ('django.template.loaders.cached.Loader', [ 'django.template.loaders.filesystem.Loader', 'django.template.loaders.app_directories.Loader', 'path.to.custom.Loader', ]), ], }, }]
笔记
所有内置的 Django 模板标签都可以安全地与缓存的加载器一起使用,但是如果您使用来自第三方包的自定义模板标签,或者您自己编写的,您应该确保 [X218X ] 每个标签的实现都是线程安全的。 有关更多信息,请参阅 模板标记线程安全注意事项 。
django.template.loaders.locmem.Loader
- class locmem.Loader
从 Python 字典加载模板。 这对测试很有用。
这个加载器将模板字典作为它的第一个参数:
TEMPLATES = [{ 'BACKEND': 'django.template.backends.django.DjangoTemplates', 'OPTIONS': { 'loaders': [ ('django.template.loaders.locmem.Loader', { 'index.html': 'content here', }), ], }, }]
默认情况下禁用此加载程序。
Django 根据 'loaders'
选项按顺序使用模板加载器。 它使用每个加载器,直到加载器找到匹配项。
自定义装载机
可以使用自定义模板加载器从其他来源加载模板。 自定义 Loader
类应继承自 django.template.loaders.base.Loader
并定义 get_contents()
和 get_template_sources()
方法。
加载器方法
- class Loader
从给定的源加载模板,例如文件系统或数据库。
- get_template_sources(template_name)
一种采用
template_name
并为每个可能的来源生成 Origin 实例的方法。例如,文件系统加载器可能会接收
'index.html'
作为template_name
参数。 此方法将生成index.html
的完整路径的来源,因为它出现在加载程序查看的每个模板目录中。该方法不需要验证给定路径中的模板是否存在,但应确保该路径有效。 例如,文件系统加载器确保路径位于有效的模板目录下。
- get_contents(origin)
返回给定 Origin 实例的模板的内容。
这是文件系统加载器从文件系统读取内容,或者数据库加载器从数据库读取的地方。 如果匹配的模板不存在,这应该会引发 TemplateDoesNotExist 错误。
- get_template(template_name, skip=None)
通过循环来自 get_template_sources() 的结果并调用 get_contents(),返回给定
template_name
的Template
对象。 这将返回第一个匹配模板。 如果未找到模板,则引发 TemplateDoesNotExist。可选的
skip
参数是扩展模板时要忽略的来源列表。 这允许模板扩展同名的其他模板。 它还用于避免递归错误。一般来说,为自定义模板加载器定义 get_template_sources() 和 get_contents() 就足够了。
get_template()
通常不需要被覆盖。
模板来源
模板有一个 origin
包含属性,具体取决于它们加载的来源。
- class Origin(name, template_name=None, loader=None)
- name
模板加载器返回的模板路径。 对于从文件系统读取的加载程序,这是模板的完整路径。
如果模板是直接实例化而不是通过模板加载器实例化,则这是
<unknown_source>
的字符串值。
- template_name
传递给模板加载器的模板的相对路径。
如果模板是直接实例化而不是通过模板加载器实例化,则为
None
。
- loader
构造这个
Origin
的模板加载器实例。如果模板是直接实例化而不是通过模板加载器实例化,则为
None
。django.template.loaders.cached.Loader 要求其所有包装的加载器设置此属性,通常通过使用
loader=self
实例化Origin
。