模板

作为一个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模板语言

句法

关于本节

这是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 }}

如果变量解析为可调用变量,模板系统将不带参数调用它,并使用其结果而不是可调用变量。

标签

标记在呈现过程中提供任意逻辑。

这个定义故意含糊不清。例如,标记可以输出内容,充当控制结构,例如“if”语句或“for”循环,从数据库中获取内容,甚至允许访问其他模板标记。

标签周围有 {%%} 如下所示:

{% csrf_token %}

大多数标记接受参数:

{% cycle 'odd' 'even' %}

某些标记需要开始标记和结束标记:

{% if user.is_authenticated %}Hello, {{ user.username }}.{% endif %}

A reference of built-in tags 还有 instructions for writing custom tags .

过滤器

过滤器转换变量和标记参数的值。

它们看起来是这样的:

{{ 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。

context

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.pystartproject 命令定义了一个更有用的值:

TEMPLATES = [
    {
        "BACKEND": "django.template.backends.django.DjangoTemplates",
        "DIRS": [],
        "APP_DIRS": True,
        "OPTIONS": {
            # ... some options here ...
        },
    },
]

BACKEND 是实现Django的模板后端API的模板引擎类的点式python路径。内置的后端是 django.template.backends.django.DjangoTemplatesdjango.template.backends.jinja2.Jinja2 .

由于大多数引擎从文件加载模板,因此每个引擎的顶级配置包含两个常见设置:

  • DIRS 定义引擎应按搜索顺序查找模板源文件的目录列表。

  • APP_DIRS 指示引擎是否应在已安装的应用程序中查找模板。每个后端都为应用程序中的子目录定义了一个常规名称,应用程序中的模板应存储在该目录中。

虽然不常见,但可以使用不同的选项配置同一后端的多个实例。在这种情况下,您应该定义一个 NAME 对于每个引擎。

OPTIONS 包含后端特定的设置。

使用

这个 django.template.loader 模块定义两个函数来加载模板。

get_template(template_name, using=None)[源代码]

此函数加载具有给定名称的模板并返回 Template 对象。

返回值的确切类型取决于加载模板的后端。每个后端都有自己的 Template 类。

get_template() 依次尝试每个模板引擎,直到成功为止。如果找不到模板,它将引发 TemplateDoesNotExist . 如果找到模板但包含无效语法,则会引发 TemplateSyntaxError .

如何搜索和加载模板取决于每个引擎的后端和配置。

如果要将搜索限制到特定的模板引擎,请传递引擎的 NAMEusing 参数。

select_template(template_name_list, using=None)[源代码]

select_template() 就像是 get_template() ,但需要一个模板名称列表。它按顺序尝试每个名称,并返回存在的第一个模板。

如果加载模板失败,则在中定义的以下两个异常 django.template ,可以提高:

exception TemplateDoesNotExist(msg, tried=None, backend=None, chain=None)[源代码]

在找不到模板时引发此异常。它接受以下可选参数来填充 template postmortem 在“调试”页上:

backend

产生异常的模板后端实例。

tried

查找模板时尝试的源列表。这被格式化为包含 (origin, status) 在哪里 origin 是一个 origin-like status 是一个字符串,说明找不到模板的原因。

chain

中间人名单 TemplateDoesNotExist 尝试加载模板时引发异常。它由函数使用,例如 get_template() 尝试从多个引擎加载给定模板。

exception TemplateSyntaxError(msg)[源代码]

找到模板但包含错误时引发此异常。

Template 返回的对象 get_template()select_template() 必须提供 render() 具有以下签名的方法:

Template.render(context=None, request=None)

使用给定的上下文呈现此模板。

如果 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(template_name, context=None, request=None, using=None)[源代码]

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 适合从视野返回。

最后,您可以直接使用配置的引擎:

engines

模板引擎可用于 django.template.engines ::

from django.template import engines

django_engine = engines["django"]
template = django_engine.from_string("Hello {{ name }}!")

查找键- 'django' 在本例中-是引擎的 NAME .

内置后端

class DjangoTemplates[源代码]

集合 BACKEND'django.template.backends.django.DjangoTemplates' 配置django模板引擎。

什么时候? APP_DIRSTrueDjangoTemplates 引擎在中查找模板 templates 已安装应用程序的子目录。为了向后兼容,保留了这个通用名称。

DjangoTemplates 引擎接受以下条件 OPTIONS

  • 'autoescape' :控制是否启用HTML自动转义的布尔值。

    它默认为 True .

    警告

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

  • 'context_processors' :指向可调用文件的点式python路径列表,用于在用请求呈现模板时填充上下文。这些可调用对象将请求对象作为其参数,并返回 dict 要合并到上下文中的项。

    它默认为空列表。

    RequestContext 更多信息。

  • 'debug' :打开/关闭模板调试模式的布尔值。如果是 True ,花式错误页将显示模板呈现期间引发的任何异常的详细报告。此报表包含模板的相关片段,并突出显示相应的行。

    它默认为 DEBUG 设置。

  • 'loaders' :指向模板加载程序类的点式python路径列表。各 Loader 类知道如何从特定源导入模板。或者,可以使用元组代替字符串。元组中的第一项应该是 Loader 类名称和后续项将传递给 Loader 初始化期间。

    默认值取决于 DIRSAPP_DIRS .

    装载器类型 有关详细信息。

  • '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 %}} 标签。

class Jinja2[源代码]

要求 Jinja2 待安装:

$ python -m pip install Jinja2
...\> py -m pip install Jinja2

集合 BACKEND'django.template.backends.jinja2.Jinja2' 配置一个 Jinja2 引擎。

什么时候? APP_DIRSTrueJinja2 引擎在中查找模板 jinja2 已安装应用程序的子目录。

最重要的进入 OPTIONS'environment' . 这是一条带点的python路径,指向返回jinja2环境的可调用路径。它默认为 'jinja2.Environment' . Django调用该可调用项并将其他选项作为关键字参数传递。此外,Django还添加了一些与Jinja2不同的默认值:

  • 'autoescape': True

  • 'loader': a loader configured for DIRS and APP_DIRS

  • '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添加上下文处理器的原始用例涉及:

    • 根据请求进行昂贵的计算。

    • 需要每个模板中的结果。

    • 在每个模板中多次使用结果。

    除非满足所有这些条件,否则将函数传递给模板更符合Jinja2的设计。

默认配置被有意地保持在最低限度。如果模板与请求一起呈现(例如在使用 render()Jinja2 后端添加全局 requestcsrf_inputcsrf_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模板语言和Jinja2中都存在,但它们的用法不同。由于Jinja2支持将参数传递给模板中的可调用项,许多需要Django模板中的模板标记或过滤器的特性可以通过调用Jinja2模板中的函数来实现,如上面的示例所示。Jinja2的全局命名空间消除了对模板上下文处理器的需要。Django模板语言没有Jinja2测试的等价物。