Django 模板语言:面向 Python 程序员 — Django 文档

来自菜鸟教程
Django/docs/2.2.x/ref/templates/api
跳转至:导航、​搜索

Django 模板语言:对于 Python 开发者

本文档从技术角度解释了 Django 模板系统——它是如何工作的以及如何扩展它。 如果您只是在寻找语言语法方面的参考,请参阅 Django 模板语言

它假定您了解模板、上下文、变量、标签和渲染。 如果您不熟悉这些概念,请从 对 Django 模板语言 的介绍开始。

概况

在 Python 中使用模板系统是一个三步走的过程:

  1. 您配置 引擎
  2. 您将模板代码编译为 Template
  3. 您使用 上下文 渲染模板。

Django 项目通常依赖 高级、后端不可知 API 来执行这些步骤中的每一步,而不是模板系统的低级 API:

  1. 对于 :setting:`TEMPLATES` 设置中的每个 DjangoTemplates 后端,Django 实例化一个 EngineDjangoTemplates 包装了 Engine 并使其适应了通用模板后端 API。
  2. django.template.loader 模块提供了get_template() 等函数来加载模板。 他们返回一个 django.template.backends.django.Template,它包装了实际的 django.template.Template
  3. 在上一步中获得的 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_dirsTrue

    如果 debugFalse,这些加载器被包裹在 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."

变量和查找

变量名称必须由任何字母(A-Z)、任何数字(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 设置为任何其他值,变量过滤器将被忽略。

对于 ifforregroup 模板标签,此行为略有不同。 如果为这些模板标签之一提供了无效变量,则该变量将被解释为 None。 过滤器始终应用于这些模板标签中的无效变量。

如果 string_if_invalid 包含 '%s',格式标记将被替换为无效变量的名称。

仅供调试使用!

虽然 string_if_invalid 是一个有用的调试工具,但将其作为“开发默认值”打开是个坏主意。

当遇到不存在的变量时,许多模板,包括一些 Django 的模板,都依赖于模板系统的沉默。 如果您将 以外的值分配给 string_if_invalid,您将遇到这些模板和网站的渲染问题。

一般情况下,string_if_invalid只应在调试特定模板问题时启用,调试完成后清除。


内置变量

每个上下文都包含 TrueFalseNone。 如您所料,这些变量解析为相应的 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 在上下文中,则返回其值。 否则插入值为 defaultkey 并返回 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() 的结果可用于单元测试以比较 Contextdict

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 选项中关闭。

每个处理器按顺序应用。 这意味着,如果一个处理器向上下文添加一个变量,而第二个处理器添加一个同名的变量,则第二个将覆盖第一个。 默认处理器解释如下。

当应用上下文处理器时

上下文处理器应用于上下文数据之上。 这意味着上下文处理器可能会覆盖您提供给 ContextRequestContext 的变量,因此请注意避免变量名称与上下文处理器提供的变量名称重叠。

如果您希望上下文数据优先于上下文处理器,请使用以下模式:

from django.template import RequestContext

request_context = RequestContext(request)
request_context.push({"my_name": "Adrian"})

Django 这样做是为了允许上下文数据覆盖 API 中的上下文处理器,例如 render()TemplateResponse


此外,您可以使用可选的第三个位置参数 processorsRequestContext 提供附加处理器列表。 在这个例子中, 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 实例,如果客户端未登录)。
  • permsdjango.contrib.auth.context_processors.PermWrapper 的一个实例,代表当前登录用户拥有的权限。


django.template.context_processors.debug

debug()

如果启用此处理器,则每个 RequestContext 将包含这两个变量 - 但前提是您的 :setting:`DEBUG` 设置设置为 True 和请求的 IP 地址(request.META['REMOTE_ADDR']) 在 :setting:`INTERNAL_IPS` 设置中:

  • debugTrue。 您可以在模板中使用它来测试您是否处于 :setting:`DEBUG` 模式。
  • sql_queries{'sql': ..., 'time': ...} 字典的列表,表示到目前为止在请求期间发生的每个 SQL 查询以及花费了多长时间。 该列表按数据库别名排序,然后按查询排序。 它是在访问时惰性生成的。


django.template.context_processors.i18n

i18n()

如果启用此处理器,则每个 RequestContext 将包含以下变量:

  • LANGUAGES:setting:`LANGUAGES` 设置的值。
  • LANGUAGE_BIDITrue 如果当前语言是从右到左的语言,例如 希伯来语、阿拉伯语。 False 如果是从左到右的语言,例如 英语、法语、德语。
  • LANGUAGE_CODErequest.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.csrf

该处理器添加了 :ttag:`csrf_token` 模板标签所需的令牌,以防止 跨站点请求伪造


django.template.context_processors.request

如果启用该处理器,则每个 RequestContext 将包含一个变量 request,即当前的 HttpRequest


django.template.context_processors.tz

tz()

如果启用此处理器,每个 RequestContext 将包含一个变量 TIME_ZONE,提供当前活动时区的名称。


django.contrib.messages.context_processors.messages

如果启用此处理器,则每个 RequestContext 将包含以下两个变量:

  • messages – 已通过 消息框架 设置的消息列表(作为字符串)。
  • DEFAULT_MESSAGE_LEVELS – 消息级别名称到 其数值 的映射。


编写你自己的上下文处理器

上下文处理器有一个非常简单的接口:它是一个 Python 函数,它接受一个参数,一个 HttpRequest 对象,并返回一个添加到模板上下文的字典。 每个上下文处理器 必须 返回一个字典。

自定义上下文处理器可以存在于您的代码库中的任何位置。 所有 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,也可以根本没有扩展名。

请注意,这些路径应该使用 Unix 风格的斜线,即使在 Windows 上也是如此。


加载器类型

默认情况下,Django 使用的是基于文件系统的模板加载器,但 Django 自带了一些其他的模板加载器,它们知道如何从其他来源加载模板。

这些其他加载器中的一些默认情况下是禁用的,但您可以通过在 :setting:`TEMPLATES` 设置或 DjangoTemplates 后端添加 'loaders' 选项来激活它们将 loaders 参数传递给 Engineloaders 应该是一个字符串或元组的列表,其中每个代表一个模板加载器类。 以下是 Django 附带的模板加载器:

django.template.loaders.filesystem.Loader

class filesystem.Loader

从文件系统加载模板,根据 :setting:`目录 ` .

默认情况下启用此加载程序。 但是,在您设置之前它不会找到任何模板 :setting:`目录 ` 到非空列表:

TEMPLATES = [{
    'BACKEND': 'django.template.backends.django.DjangoTemplates',
    'DIRS': [os.path.join(BASE_DIR, 'templates')],
}]

您还可以覆盖 'DIRS' 并为特定文件系统加载器指定特定目录:

TEMPLATES = [{
    'BACKEND': 'django.template.backends.django.DjangoTemplates',
    'OPTIONS': {
        'loaders': [
            (
                'django.template.loaders.filesystem.Loader',
                [os.path.join(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.pollsdjango.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': [os.path.join(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_nameTemplate 对象。 这将返回第一个匹配模板。 如果未找到模板,则引发 TemplateDoesNotExist

可选的 skip 参数是扩展模板时要忽略的来源列表。 这允许模板扩展同名的其他模板。 它还用于避免递归错误。

一般来说,为自定义模板加载器定义 get_template_sources()get_contents() 就足够了。 get_template() 通常不需要被覆盖。

构建你自己的

例如,阅读 :source:`Django 内置加载器的源代码 ` .


模板起源

模板有一个 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