模板

作为一个 Web 框架,Django 需要一种便捷的方式来动态生成 HTML。最常见的方法依赖于模板。模板包含所需 HTML 输出的静态部分,以及一些描述如何插入动态内容的特殊语法。有关使用模板创建 HTML 页面的实际示例,请参阅 教程 3

一个 Django 项目可以配置一个或多个模板引擎(或者如果不用模板则可以配置为零)。Django 附带了其自身模板系统(创造性地称为 Django 模板语言 (DTL))和流行的替代方案 Jinja2 的内置后端。其他模板语言的后端可能可以从第三方获得。您还可以编写自己的自定义后端,请参阅 自定义模板后端

Django 定义了一个标准的 API,用于加载和渲染模板,而不管后端是什么。加载包括为给定的标识符查找模板并对其进行预处理,通常将其编译为内存中的表示形式。渲染意味着使用上下文数据内插模板并返回结果字符串。

Django 模板语言 是 Django 自身的模板系统。在 Django 1.8 之前,它是唯一可用的内置选项。它是一个很好的模板库,尽管它相当有主见并且有一些特性。如果您没有充分的理由选择其他后端,则应使用 DTL,尤其是在编写可插拔应用程序并打算分发模板时。包含模板的 Django 的 contrib 应用程序(如 django.contrib.admin)使用 DTL。

出于历史原因,模板引擎的通用支持和 Django 模板语言的实现都位于 django.template 命名空间中。

警告

模板系统对于不受信任的模板作者来说是不安全的。例如,站点不应该允许其用户提供自己的模板,因为模板作者可以执行诸如执行 XSS 攻击和访问可能包含敏感信息的模板变量的属性等操作。

Django 模板语言

语法

关于本节

这是 Django 模板语言语法的概述。有关详细信息,请参阅 语言语法参考

Django 模板是用 Django 模板语言标记的文本文档或 Python 字符串。某些结构会被模板引擎识别和解释。主要的是变量和标签。

模板使用上下文进行渲染。渲染会将变量替换为其值(在上下文中查找),并执行标签。其他所有内容都按原样输出。

Django 模板语言的语法涉及四种结构。

变量

变量输出来自上下文的值,上下文是一个类似字典的对象,它将键映射到值。

变量用 {{}} 括起来,如下所示

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

内置标签参考 以及 编写自定义标签的说明 可供使用。

过滤器

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

它们如下所示

{{ django|title }}

{'django': 'the web framework for perfectionists with deadlines'} 的上下文中,此模板渲染为

The Web Framework For Perfectionists With Deadlines

某些过滤器采用参数

{{ my_date|date:"Y-m-d" }}

内置过滤器参考 以及 编写自定义过滤器的说明 可供使用。

注释

注释如下所示

{# this won't be rendered #}

{% comment %} 标签提供多行注释。

组件

关于本节

这是 Django 模板语言 API 的概述。有关详细信息,请参阅 API 参考

引擎

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。

上下文

django.template.Context 除了上下文数据外,还保存一些元数据。它传递给 Template.render() 以渲染模板。

django.template.RequestContextContext 的子类,它存储当前的 HttpRequest 并运行模板上下文处理器。

通用 API 没有等效的概念。上下文数据以普通的 dict 传递,如果需要,则单独传递当前的 HttpRequest

加载器

模板加载器负责定位模板、加载它们并返回 Template 对象。

Django 提供了几个 内置模板加载器 并支持 自定义模板加载器

上下文处理器

上下文处理器是接收当前 HttpRequest 作为参数并返回要添加到渲染上下文的 dict 数据的函数。

它们的主要用途是在不重复每个视图中的代码的情况下,将所有模板共享的公共数据添加到上下文中。

Django 提供了许多 内置上下文处理器,您也可以实现自己的其他上下文处理器。

模板引擎支持

配置

模板引擎使用 TEMPLATES 设置进行配置。它是一个配置列表,每个引擎一个。默认值为“空”。 startproject 命令生成的 settings.py 定义了一个更有用的值

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

BACKEND 是一个点分隔的 Python 路径,指向实现 Django 模板后端 API 的模板引擎类。内置的后端包括 django.template.backends.django.DjangoTemplatesdjango.template.backends.jinja2.Jinja2

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

  • DIRS 定义了一个目录列表,引擎应该按照搜索顺序在这些目录中查找模板源文件。

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

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

OPTIONS 包含特定于后端的设置。

用法

django.template.loader 模块定义了两个用于加载模板的函数。

get_template(template_name, using=None)[source]

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

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

get_template() 按顺序尝试每个模板引擎,直到其中一个成功。如果找不到模板,它将引发 TemplateDoesNotExist。如果找到模板但包含无效语法,则会引发 TemplateSyntaxError

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

如果要将搜索限制到特定的模板引擎,请在 using 参数中传递引擎的 NAME

select_template(template_name_list, using=None)[source]

select_template() 类似于 get_template(),只是它接受一个模板名称列表。它按顺序尝试每个名称,并返回第一个存在的模板。

如果加载模板失败,则可能会引发以下两个异常(在 django.template 中定义)

exception TemplateDoesNotExist(msg, tried=None, backend=None, chain=None)[source]

当找不到模板时,会引发此异常。它接受以下可选参数,用于填充调试页面上的 模板事后分析

backend

引发异常的模板后端实例。

tried

查找模板时尝试过的源列表。它被格式化为包含 (origin, status) 的元组列表,其中 origin 是一个 类似源 的对象,而 status 是一个字符串,说明找不到模板的原因。

chain

尝试加载模板时引发的中间 TemplateDoesNotExist 异常列表。这由诸如 get_template() 之类的函数使用,这些函数尝试从多个引擎加载给定模板。

exception TemplateSyntaxError(msg)[source]

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

get_template()select_template() 返回的 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)[source]

render_to_string() 加载模板,类似于 get_template(),并立即调用其 render() 方法。它接受以下参数。

template_name

要加载和渲染的模板名称。如果它是一个模板名称列表,Django 会使用 select_template() 而不是 get_template() 来查找模板。

context

一个 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,该 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[source]

BACKEND 设置为 'django.template.backends.django.DjangoTemplates' 以配置 Django 模板引擎。

APP_DIRSTrue 时,DjangoTemplates 引擎会在已安装应用程序的 templates 子目录中查找模板。此通用名称保留是为了向后兼容。

DjangoTemplates 引擎接受以下 OPTIONS

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

    默认为 True

    警告

    仅当您正在渲染非 HTML 模板时才将其设置为 False

  • '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 路径列表,用于添加到 内置。例如

    OPTIONS = {
        "builtins": ["myapp.builtins"],
    }
    

    无需先调用 {% load %} 标签,即可使用内置库中的标签和过滤器。

class Jinja2[source]

需要安装 Jinja2

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

BACKEND 设置为 'django.template.backends.jinja2.Jinja2' 以配置 Jinja2 引擎。

APP_DIRSTrue 时,Jinja2 引擎会在已安装应用程序的 jinja2 子目录中查找模板。

OPTIONS 中最重要的条目是 'environment'。它是一个点分隔的 Python 可调用对象路径,用于返回 Jinja2 环境。默认为 'jinja2.Environment'。Django 会调用该可调用对象并将其他选项作为关键字参数传递。此外,Django 为一些选项添加了与 Jinja2 不同的默认值

  • 'autoescape'True

  • 'loader':为 DIRSAPP_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测试等效的功能。

返回顶部