Django模板语言:针对Python程序员

本文从技术角度解释了Django模板系统——它是如何工作的以及如何扩展它。如果要查找有关语言语法的参考,请参阅 Django模板语言 .

它假定理解模板、上下文、变量、标记和呈现。从开始 introduction to the Django template language 如果你不熟悉这些概念。

概述

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

  1. 您配置了 Engine .

  2. 将模板代码编译为 Template .

  3. 使用 Context .

Django项目通常依赖 high level, backend agnostic APIs 对于这些步骤中的每一个,而不是模板系统的低级API:

  1. 对于每一个 DjangoTemplates 后端在 TEMPLATES 设置,Django实例化 Engine . DjangoTemplatesEngine 并使其适应通用模板后端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 .

    警告

    只将它设置为 False 如果要呈现非HTML模板!

  • 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 .

    然后将这些装载机包裹在 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",
        },
    )
    

    通过将相应的字典键传递给 {{% load %}} 标签。

  • 'builtins' :要添加到的模板标记模块的点式python路径列表 built-ins . 例如::

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

    可以使用内置库中的标记和筛选器,而无需首先调用 {{% load %}} 标签。

static Engine.get_default()[源代码]

返回基础 Engine 从第一次配置 DjangoTemplates 引擎。加薪 ImproperlyConfigured 如果没有配置引擎。

它需要保留依赖于全局可用、隐式配置的引擎的API。任何其他用途都是强烈反对的。

Engine.from_string(template_code)[源代码]

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

Engine.get_template(template_name)[源代码]

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

Engine.select_template(template_name_list)[源代码]

喜欢 get_template() ,但它接受名称列表并返回找到的第一个模板。

加载模板

创建 Template 是通过调用 Engineget_template()select_template()from_string() .

在Django项目中, TEMPLATES 设置定义了 DjangoTemplates 引擎,可以实例化 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 接受可选参数-将变量名映射到变量值的字典。

有关详细信息,请参阅 玩弄 Context 对象 下面。

Template.render(context)[源代码]

调用 Template 对象的 render() 方法,并使用 Context “填写”模板的步骤:

>>> 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]

注意模板表达式中的“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."

可调用变量比只需要直接查找的变量稍微复杂一些。以下是一些需要牢记的事项:

  • 如果变量在调用时引发异常,则将传播该异常,除非该异常具有属性 silent_variable_failure 它的价值是 True 。如果异常 does vbl.有一个 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 选择权。

  • 调用一些变量时可能会有副作用,允许模板系统访问这些变量是愚蠢的,或者是一个安全漏洞。

    一个很好的例子是 delete() 在每个Django模型对象上使用。模板系统不应该被允许做这样的事情:

    I will now delete this valuable data. {{ data.delete }}
    

    要防止这种情况,请设置 alters_data 可调用变量的属性。模板系统不会调用变量,如果它有 alters_data=True 设置,并将用替换变量 string_if_invalid ,无条件。动态生成的 delete()save() Django模型对象的方法 alters_data=True 自动地。例子::

    def sensitive_function(self):
        self.database_record.delete()
    
    
    sensitive_function.alters_data = True
    
  • 有时,您可能希望出于其他原因关闭此功能,并告诉模板系统,不管怎样,都不要调用变量。为此,设置一个 do_not_call_in_templates 具有值的可调用文件的属性 True . 然后,模板系统将充当变量不可调用的角色(例如,允许您访问可调用的属性)。

如何处理无效变量

通常,如果变量不存在,模板系统会插入引擎的值 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的模板语言无法转义用于自身语法的字符。例如, 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 在上下文中,返回其值。否则插入 key 具有价值 default 回报 default .

Context.pop()
Context.push()
exception ContextPopException[源代码]

A 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() , the 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'

使用A Context 当一堆东西在 some custom template tags .

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'}

A 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 选择权。

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

当应用上下文处理器时

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

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

from django.template import RequestContext

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

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

另外,你可以给 RequestContext 使用可选的第三个位置参数的附加处理器列表, processors . 在这个例子中, 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(request)[源代码]

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

  • user ——安 auth.User 表示当前登录用户(或 AnonymousUser 实例,如果客户端未登录)。

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

django.template.context_processors.debug

debug(request)[源代码]

如果启用此处理器,则每个 RequestContext 将包含这两个变量——但仅当 DEBUG 设置设置为 True 以及请求的IP地址 (request.META['REMOTE_ADDR'] 是在 INTERNAL_IPS 设置:

  • debug —— True . 你可以在模板中使用这个来测试你是否在 DEBUG 模式。

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

django.template.context_processors.i18n

i18n(request)[源代码]

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

  • LANGUAGES --的值 LANGUAGES 设置。

  • LANGUAGE_BIDI —— True 如果当前语言是从右向左的语言,例如希伯来语、阿拉伯语。 False 如果是从左到右的语言,例如英语、法语、德语。

  • LANGUAGE_CODE —— request.LANGUAGE_CODE ,如果存在。否则, LANGUAGE_CODE 设置。

i18n template tags 用于生成相同值的模板标记。

django.template.context_processors.media

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

django.template.context_processors.static

static(request)[源代码]

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

django.template.context_processors.csrf

此处理器添加了 csrf_token 模板标签以防 Cross Site Request Forgeries .

django.template.context_processors.request

如果启用此处理器,则每个 RequestContext 将包含变量 request ,哪个是电流 HttpRequest .

django.template.context_processors.tz

tz(request)[源代码]

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

django.contrib.messages.context_processors.messages

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

编写自己的上下文处理器

上下文处理器有一个简单的接口:它是一个接受一个参数、一个 HttpRequest 对象,并返回添加到模板上下文中的词典。

例如,若要添加 DEFAULT_FROM_EMAIL 设置到每个上下文::

from django.conf import settings


def from_email(request):
    return {
        "DEFAULT_FROM_EMAIL": settings.DEFAULT_FROM_EMAIL,
    }

自定义上下文处理器可以位于代码库中的任何位置。Django所关心的只是您的自定义上下文处理器被 'context_processors' 你的选择 TEMPLATES 设置-或 context_processors 的参数 Engine 如果你直接用的话。

正在加载模板

通常,您将模板存储在文件系统中的文件中,而不是使用底层 Template API。将模板保存在指定为 模板目录 .

Django根据模板加载设置在多个位置搜索模板目录(请参见下面的“加载程序类型”),但指定模板目录的最基本方法是使用 DIRS 选择权。

这个 DIRS 选项

通过使用 DIRS 期权在 TEMPLATES 设置文件中的设置-或 dirs 的参数 Engine . 应将其设置为包含到模板目录的完整路径的字符串列表:

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

只要目录和模板可由Web服务器读取,您的模板就可以转到您想要的任何位置。它们可以具有您想要的任何扩展名,例如 .html.txt ,或者它们可以根本没有延期。

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

装载器类型

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

默认情况下,其中一些加载程序被禁用,但可以通过添加 'loaders' 您的选择 DjangoTemplates 后端在 TEMPLATES 设置或通过 loaders 参数 Engine . loaders 应该是字符串或元组的列表,其中每个都表示一个模板加载程序类。以下是Django附带的模板加载程序:

django.template.loaders.filesystem.Loader

class filesystem.Loader

根据 DIRS .

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

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应用程序加载模板。对于每个应用程序 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管理,可以选择重写标准 admin/base_site.html 模板,来自 django.contrib.admin ,用你自己的 admin/base_site.html 在里面 myproject.polls . 然后你必须确保 myproject.polls之前 django.contrib.admin 在里面 INSTALLED_APPS ,否则 django.contrib.admin 将首先加载的,而您的将被忽略。

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

您可以通过设置 APP_DIRSTrue ::

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

django.template.loaders.cached.Loader

class cached.Loader

虽然Django模板系统速度很快,但如果它需要在每次呈现模板时读取和编译模板,那么由此产生的开销可能会增加。

配置缓存模板加载器时,需要包含其他加载器的列表。包装加载程序用于在第一次遇到未知模板时定位它们。然后缓存加载程序存储编译的 Template 在记忆中。缓存的 Template 为随后加载同一模板的请求返回实例。

如果出现以下情况,则自动启用此加载程序 OPTIONS['loaders'] 未指定。

您可以使用如下设置使用一些自定义模板加载器手动指定模板缓存:

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模板标记都可以安全地与缓存加载程序一起使用,但是如果您使用的是来自第三方包的自定义模板标记,或者您自己编写的模板标记,则应确保 Node 每个标记的实现都是线程安全的。有关详细信息,请参阅 template tag thread safety considerations .

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)[源代码]

返回A Template 给定对象 template_name 通过循环遍历 get_template_sources() 呼唤 get_contents() . 这将返回第一个匹配的模板。如果找不到模板, TemplateDoesNotExist 提高了。

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

一般来说,它足以定义 get_template_sources()get_contents() 用于自定义模板加载程序。 get_template() 通常不需要重写。

建立自己的

例如,阅读 source code for Django's built-in loaders .

模板原点

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

class Origin(name, template_name=None, loader=None)[源代码]
name

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

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

template_name

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

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

loader

构造此的模板加载程序实例 Origin .

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

django.template.loaders.cached.Loader 要求其所有包装的加载程序设置此属性,通常通过实例化 Origin 具有 loader=self .