Skip to main content

Django模板语言:用于Python程序员

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

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

概述

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

  1. 您配置 Engine

  2. 将模板代码编译到 Template 中。

  3. 您使用 Context 呈现模板。

Django项目通常依赖于 高级,后端不可知的API 中的每个步骤,而不是模板系统的较低级别的API:

  1. 对于 TEMPLATES 设置中的每个 DjangoTemplates 后端,Django实例化一个 EngineDjangoTemplates 封装 Engine 并将其适配到公共模板后端API。

  2. django.template.loader 模块提供了诸如 get_template() 等加载模板的功能。他们返回一个 django.template.backends.django.Template,它包装实际的 django.template.Template

  3. 在上一步骤中获得的 Template 具有 render() 方法,其将上下文和可能的请求编组到 Context 中,并将呈现委托给基础 Template

配置引擎

如果你只是使用 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

    New in Django 1.10:

    添加了 autoescape 选项。

  • 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

    有关详细信息,请参阅 装载机类型

  • 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',
        },
    )
    

    可以通过将相应的字典键传递到 {% load %} 标记来加载库。

  • 'builtins':要添加到 内置 的模板标记模块的虚拟Python路径列表。例如:

    Engine(
        builtins=['myapp.builtins'],
    )
    

    可以在不首先调用 {% load %} 标记的情况下使用来自内置库的标记和过滤器。

New in Django 1.9:

添加了 librariesbuiltins 参数。

static Engine.get_default()[源代码]

当Django项目配置一个且只有一个 DjangoTemplates 引擎时,此方法返回基础 Engine。在其他情况下,它会提高 ImproperlyConfigured

它是保留依赖于全局可用的隐式配置引擎的API所必需的。强烈建议不要使用其他用途。

Engine.from_string(template_code)[源代码]

编译给定的模板代码并返回一个 Template 对象。

Engine.get_template(template_name)[源代码]

加载具有给定名称的模板,对其进行编译并返回 Template 对象。

Engine.select_template(self, template_name_list)[源代码]

get_template(),除了它需要一个名称列表,并返回找到的第一个模板。

加载模板

推荐的创建 Template 的方法是通过调用 Engine 的工厂方法:get_template()select_template()from_string()

在一个Django项目中,TEMPLATES 设置只定义一个 DjangoTemplates 引擎,可以直接实例化一个 Template

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。构造函数接受两个可选参数:

  • 将变量名映射到变量值的字典。

  • 当前应用程序的名称。此应用程序名称用于帮助 resolve namespaced URLs。如果您不使用命名空间网址,可以忽略此参数。

有关详细信息,请参阅下面的 使用 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 具有值为 Truesilent_variable_failure 属性,则变量将呈现为引擎的 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
    
  • 有时你可能想要关闭此功能的其他原因,并告诉模板系统留下一个变量无论什么。为此,在可调用项上设置值为 Truedo_not_call_in_templates 属性。然后,模板系统将表现得好像您的变量不可调用(例如,允许您访问可调用对象的属性)。

如何处理无效变量

通常,如果变量不存在,模板系统将插入引擎的 string_if_invalid 配置选项的值,默认情况下,该选项设置为 '' (空字符串)。

应用于无效变量的过滤器将仅在 string_if_invalid 设置为 '' (空字符串)时应用。如果 string_if_invalid 设置为任何其他值,则将忽略变量过滤器。

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

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

仅用于调试目的!

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

许多模板(包括管理站点中的模板)依赖于在遇到不存在的变量时模板系统的静默。如果您将除 '' 之外的值分配给 string_if_invalid,您将遇到这些模板和网站的渲染问题。

一般来说,只有启用 string_if_invalid 才能调试特定的模板问题,然后在调试完成后清除。

内置变量

每个上下文包含 TrueFalseNone。正如你所期望的,这些变量解析为相应的Python对象。

字符串字面量的限制

Django的模板语言没有办法转义用于自己语法的字符。例如,如果需要输出如 {%%} 的字符序列,则需要 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)
New in Django 1.9.

如果 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'
New in Django 1.9:

添加了使用 update() 作为上下文管理器的能力。

使用 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'。这是管理员和其他应用程序所需的与安全相关的上下文处理器,如果意外配置错误,则会在 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 - 表示当前登录用户(或者如果客户端未登录,则为 AnonymousUser 实例)的 auth.User 实例。

  • perms - django.contrib.auth.context_processors.PermWrapper 的实例,表示当前登录的用户具有的权限。

django.template.context_processors.debug

debug()

如果启用此处理器,则每个 RequestContext 都将包含这两个变量 - 但仅当您的 DEBUG 设置设置为 True,并且请求的IP地址(request.META['REMOTE_ADDR'])处于 INTERNAL_IPS 设置时:

  • debug - True。您可以在模板中使用它来测试您是否处于 DEBUG 模式。

  • sql_queries - {'sql': ..., 'time': ...} 字典的列表,表示在请求期间到目前为止发生的每个SQL查询以及它需要多长时间。该列表按顺序按数据库别名,然后按查询。它是懒惰生成访问。

Changed in Django 1.10:

在旧版本中,仅包括缺省数据库别名的查询。

django.template.context_processors.i18n

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

  • LANGUAGES - LANGUAGES 设置的值。

  • LANGUAGE_CODE - request.LANGUAGE_CODE,如果存在。否则,LANGUAGE_CODE 设置的值。

有关更多信息,请参阅 国际化和本地化

django.template.context_processors.media

如果启用此处理器,则每个 RequestContext 将包含一个变量 MEDIA_URL,提供 MEDIA_URL 设置的值。

django.template.context_processors.static

static()

如果启用此处理器,则每个 RequestContext 将包含一个变量 STATIC_URL,提供 STATIC_URL 设置的值。

django.template.context_processors.csrf

此处理器添加 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 对象,并返回一个添加到模板上下文的字典。每个上下文处理器 must 返回一个字典。

自定义上下文处理器可以在代码库中的任何地方。所有Django关心的是,您的自定义上下文处理器由您的 TEMPLATES 设置中的 'context_processors' 选项指向 - 或者 Enginecontext_processors 参数,如果您直接使用它。

加载模板

通常,你将模板存储在文件系统的文件中,而不是自己使用低级 Template API。将模板保存在指定为 模板目录 的目录中。

Django在许多地方搜索模板目录,具体取决于你的模板加载设置(参见下面的“加载器类型”),但是最基本的指定模板目录的方法是使用 DIRS 选项。

DIRS 选项

使用设置文件中 TEMPLATES 设置中的 DIRS 选项或 Enginedirs 参数告诉Django你的模板目录是什么。这应该设置为包含模板目录的完整路径的字符串列表:

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [
            '/home/html/templates/lawrence.com',
            '/home/html/templates/default',
        ],
    },
]

只要目录和模板可由Web服务器读取,您的模板就可以放在任何位置。他们可以有任何你想要的扩展,如 .html.txt,或者他们可以没有扩展。

注意,这些路径应该使用Unix样式的正斜杠,即使在Windows上。

装载机类型

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

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

django.template.loaders.filesystem.Loader

class filesystem.Loader

根据 DIRS,从文件系统加载模板。

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

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

django.template.loaders.app_directories.Loader

class app_directories.Loader

从文件系统上的Django应用程序加载模板。对于 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/

...并将使用它首先找到的一个。

INSTALLED_APPS 的顺序是重要的!例如,如果您要自定义Django管理员,您可以选择从 django.contrib.admin 覆盖标准 admin/base_site.html 模板,在 myproject.polls 中使用您自己的 admin/base_site.html。您必须确保您的 myproject.pollsINSTALLED_APPS 中来自 before django.contrib.admin,否则将首先加载 django.contrib.admin,您的AAM将被忽略。

注意,加载器在第一次运行时执行优化:它缓存一个 INSTALLED_APPS 包有 templates 子目录的列表。

您可以通过将 APP_DIRS 设置为 True 来启用此加载器:

TEMPLATES = [{
    'BACKEND': 'django.template.backends.django.DjangoTemplates',
    'APP_DIRS': True,
}]

django.template.loaders.eggs.Loader

class eggs.Loader

1.9 版后已移除: 不推荐将应用程序分发为蛋。

就像上面的 app_directories,但它加载模板从Python鸡蛋而不是从文件系统。

默认情况下禁用此加载程序。

django.template.loaders.cached.Loader

class cached.Loader

默认情况下,模板系统将在每次需要渲染时读取和编译模板。虽然Django模板系统相当快,但读取和编译模板的开销可能会相加。

缓存模板加载器是一个基于类的加载器,您可以使用要包装的其他加载器的列表来配置。包装加载器用于在未知模板首次遇到时定位它们。缓存的加载器然后将编译的 Template 存储在存储器中。返回缓存的 Template 实例用于加载相同模板的后续请求。

例如,要使用 filesystemapp_directories 模板加载器启用模板缓存,您可以使用以下设置:

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',
            ]),
        ],
    },
}]

注解

所有内置的Django模板标签都可以安全地用于缓存加载器,但如果您使用来自第三方软件包或自己编写的自定义模板标签,则应确保每个标签的 Node 实现是线程安全的。有关详细信息,请参阅 模板标签线程安全考虑

默认情况下禁用此加载程序。

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() 方法。

Changed in Django 1.9:

在以前的Django版本中,自定义装载器定义了一个单一的方法:load_template_source()

加载器方法

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() 通常不需要被覆盖。

load_template_source(template_name, template_dirs=None)[源代码]

返回(template_stringtemplate_origin)的元组,其中 template_string 是包含模板内容的字符串,template_origin 是标识模板源的字符串。基于文件系统的加载器可以返回例如作为 template_origin 的文件的完整路径。

template_dirs 是一个可选参数,用于控制加载程序将搜索哪些目录。

此方法由 load_template() 自动调用,并且在编写自定义模板加载程序时应被覆盖。

1.9 版后已移除: 自定义装载器应该使用 get_template()get_contents()

load_template(template_name, template_dirs=None)[源代码]

返回(templatetemplate_origin)的元组,其中 templateTemplate 对象,template_origin 是标识模板源的字符串。基于文件系统的加载器可以返回例如作为 template_origin 的文件的完整路径。

1.9 版后已移除: 自定义装载器应该使用 get_template()get_contents()

模板起源

模板具有包含属性的 origin,这取决于它们从中加载的来源。

Changed in Django 1.9:

Django用来创建一个基于 django.template.loader.LoaderOrigindjango.template.base.StringOrigin 的原点。这些已被 django.template.base.Origin 取代。

class Origin[源代码]
name

模板加载器返回的模板路径。对于从文件系统读取的加载器,这是模板的完整路径。

如果模板直接实例化而不是通过模板加载器,则这是 <unknown_source> 的字符串值。

template_name

传递到模板加载器的模板的相对路径。

如果模板是直接实例化而不是通过模板加载器,这是 None