Skip to main content

模板

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

Django项目可以配置一个或多个模板引擎(如果不使用模板,甚至为零)。 Django为自己的模板系统内置了后端,创造性地称为Django模板语言(DTL),并为流行的替代 Jinja2。其他模板语言的后端可以从第三方获得。

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

Django模板语言 是Django自己的模板系统。直到Django 1.8它是唯一的内置选项可用。这是一个很好的模板库,即使它是相当褒扬和运动几个特点。如果你没有迫切的理由选择另一个后端,你应该使用DTL,特别是如果你编写一个可插入的应用程序,并且你打算分发模板。 Django的包含模板的应用程序,如 django.contrib.admin,使用DTL。

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

支持模板引擎

组态

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

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

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

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

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

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

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

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

当无法找到模板时引发此异常。它接受以下可选参数,用于在调试页面上填充 模板postmortem

backend

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

tried

找到模板时尝试的源的列表。这被格式化为包含 (origin, status) 的元组的列表,其中 origin原产地 对象,status 是具有未找到模板的原因的字符串。

chain

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

New in Django 1.9:

添加了 backendtriedchain 参数。

exception TemplateSyntaxError(msg)[源代码]

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

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找到一个存在的模板时,它停止查找。

小费

您可以使用 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

dict 用作模板的上下文进行渲染。

request

在模板的渲染过程中可用的可选 HttpRequest

using

可选的模板引擎 NAME。模板的搜索将仅限于该引擎。

用法示例:

from django.template.loader import render_to_string
rendered = render_to_string('my_template.html', {'foo': 'bar'})

另请参阅调用 render_to_string()render() 快捷方式,并将结果馈送到适合从视图返回的 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_DIRSTrue 时,DjangoTemplates 引擎在已安装应用程序的 templates 子目录中查找模板。此通用名称保留用于向后兼容性。

DjangoTemplates 引擎接受以下 OPTIONS

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

    它默认为 True

    警告

    如果您正在呈现非HTML模板,请将其设置为 False

    New in Django 1.10:

    添加了 autoescape 选项。

  • 'context_processors':用于在使用请求呈现模板时用于填充上下文的可调用对象的点状Python路径列表。这些可调用包含一个请求对象作为它们的参数,并返回一个要合并到上下文中的项目的 dict

    它默认为空列表。

    有关详细信息,请参阅 RequestContext

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

    它默认为 DEBUG 设置的值。

  • 'loaders':模板加载器类的虚拟Python路径列表。每个 Loader 类都知道如何从特定源导入模板。可选地,可以使用元组而不是字符串。元组中的第一个项应该是 Loader 类名,并且在初始化期间将后续项传递给 Loader

    默认值取决于 DIRSAPP_DIRS 的值。

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

  • 'string_if_invalid':模板系统应用于无效(例如拼写错误)变量的输出,作为字符串。

    它默认为空字符串。

    有关详细信息,请参阅 如何处理无效变量

  • 'file_charset':用于读取磁盘上的模板文件的字符集。

    它默认为 FILE_CHARSET 的值。

  • '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 %} 标记的情况下使用来自内置库的标记和过滤器。

New in Django 1.9:

添加了 librariesbuiltins 参数。

class Jinja2

需要安装 Jinja2

$ pip install Jinja2

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

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

OPTIONS 中最重要的条目是 'environment'。这是一个虚线的Python路径到一个callable返回一个Jinja2环境。它默认为 'jinja2.Environment'。 Django调用该可调用项并传递其他选项作为关键字参数。此外,Django添加了不同于Jinja2的默认值几个选项:

  • 'autoescape'True

  • 'loader':为 DIRSAPP_DIRS 配置的加载程序

  • 'auto_reload'settings.DEBUG

  • 'undefined'DebugUndefined if settings.DEBUG else Undefined

有意将默认配置保持为最小。如果使用请求(例如,当使用 render() 时)呈现模板时,Jinja2 后端将全局变量 requestcsrf_inputcsrf_token 添加到上下文。除此之外,这个后端不创建一个Django风味的环境。它不知道Django上下文处理器,过滤器和标签。为了使用Django特定的API,您必须将它们配置到环境中。

例如,您可以使用此内容创建 myproject/jinja2.py:

from __future__ import absolute_import  # Python 2 only

from django.contrib.staticfiles.storage import staticfiles_storage
from django.urls import reverse

from jinja2 import Environment


def environment(**options):
    env = Environment(**options)
    env.globals.update({
        'static': staticfiles_storage.url,
        '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测试的等价物。

自定义后端

以下是如何实现自定义模板后端,以便使用其他模板系统。模板后端是继承 django.template.backends.base.BaseEngine 的类。它必须实现 get_template() 和可选的 from_string()。这里有一个虚构的 foobar 模板库的例子:

from django.template import TemplateDoesNotExist, TemplateSyntaxError
from django.template.backends.base import BaseEngine
from django.template.backends.utils import csrf_input_lazy, csrf_token_lazy

import foobar


class FooBar(BaseEngine):

    # Name of the subdirectory containing the templates for this engine
    # inside an installed application.
    app_dirname = 'foobar'

    def __init__(self, params):
        params = params.copy()
        options = params.pop('OPTIONS').copy()
        super(FooBar, self).__init__(params)

        self.engine = foobar.Engine(**options)

    def from_string(self, template_code):
        try:
          return Template(self.engine.from_string(template_code))
        except foobar.TemplateCompilationFailed as exc:
            raise TemplateSyntaxError(exc.args)

    def get_template(self, template_name):
        try:
            return Template(self.engine.get_template(template_name))
        except foobar.TemplateNotFound as exc:
            raise TemplateDoesNotExist(exc.args, backend=self)
        except foobar.TemplateCompilationFailed as exc:
            raise TemplateSyntaxError(exc.args)


class Template(object):

    def __init__(self, template):
        self.template = template

    def render(self, context=None, request=None):
        if context is None:
            context = {}
        if request is not None:
            context['request'] = request
            context['csrf_input'] = csrf_input_lazy(request)
            context['csrf_token'] = csrf_token_lazy(request)
        return self.template.render(context)

有关详细信息,请参阅 DEP 182

定制引擎的调试集成

New in Django 1.9:

添加了非Django模板引擎的调试页面集成。

Django调试页面具有钩子,以在模板错误出现时提供详细信息。自定义模板引擎可以使用这些钩子来增强向用户显示的回溯信息。以下钩子可用:

模板postmortem

TemplateDoesNotExist 升起时,死后出现。它列出了在尝试查找给定模板时使用的模板引擎和加载器。例如,如果配置了两个Django引擎,则事后停止将显示为:

../../_images/postmortem.png

自定义引擎可以通过在提高 TemplateDoesNotExist 时传递 backendtried 参数来填充事后死亡。在模板对象上使用事后预测 应指定原点 的后端。

上下文行信息

如果在模板解析或渲染期间发生错误,Django可以显示发生错误的行。例如:

../../_images/template-lines.png

自定义引擎可以通过在解析和呈现期间引发的异常上设置 template_debug 属性来填充此信息。此属性是具有以下值的 dict

  • 'name':发生异常的模板的名称。

  • 'message':异常消息。

  • 'source_lines':发生异常的行前,后和行的行。这是为了上下文,所以它不应该包含超过20行左右。

  • 'line':发生异常的行号。

  • 'before':引发错误的令牌之前的错误行上的内容。

  • 'during':引发错误的令牌。

  • 'after':引发错误的令牌之后的错误行上的内容。

  • 'total'source_lines 中的行数。

  • 'top'source_lines 开始的行号。

  • 'bottom'source_lines 结束的行号。

给定上述模板错误,template_debug 将看起来像:

{
    'name': '/path/to/template.html',
    'message': "Invalid block tag: 'syntax'",
    'source_lines': [
        (1, 'some\n'),
        (2, 'lines\n'),
        (3, 'before\n'),
        (4, 'Hello {% syntax error %} {{ world }}\n'),
        (5, 'some\n'),
        (6, 'lines\n'),
        (7, 'after\n'),
        (8, ''),
    ],
    'line': 4,
    'before': 'Hello ',
    'during': '{% syntax error %}',
    'after': ' {{ world }}\n',
    'total': 9,
    'bottom': 9,
    'top': 1,
}

Origin API和第三方集成

Django模板具有通过 template.origin 属性可用的 Origin 对象。这使得调试信息能够显示在 模板postmortem 中,以及第三方库(如 Django Debug Toolbar)中。

自定义引擎可以通过创建指定以下属性的对象来提供自己的 template.origin 信息:

  • 'name':模板的完整路径。

  • 'template_name':传递到模板加载方法的模板的相对路径。

  • 'loader_name':一个可选字符串,标识用于加载模板的函数或类,例如。 django.template.loaders.filesystem.Loader

Django模板语言

句法

关于本节

这是Django模板语言的语法的概述。详情请参阅 语言语法参考

Django模板只是一个文本文档或使用Django模板语言标记的Python字符串。一些构造由模板引擎识别和解释。主要的是变量和标签。

使用上下文呈现模板。 Rendering将变量替换为在上下文中查找的变量,并执行标签。一切都是按原样输出。

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提供了许多 内置上下文处理器。实现自定义上下文处理器就像定义一个函数一样简单。