模板¶ T0>

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

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

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

The Django template language is Django’s own template system. 直到Django 1.8,它是唯一可用的内置选项。 这是一个很好的模板库,尽管它是相当自以为是,并体育一些特质。 如果您没有迫切的理由选择另一个后端,则应该使用DTL,特别是在编写可插入应用程序时,如果您打算分发模板。 包含模板(如django.contrib.admin)的Django的contrib应用程序使用DTL。

由于历史原因,对模板引擎的一般支持和Django模板语言的实现都存在于django.template命名空间中。

警告

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

支持模板引擎

配置¶ T0>

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

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

BACKEND is a dotted Python path to a template engine class implementing Django’s template backend API. 内置的后端是django.template.backends.django.DjangoTemplatesdjango.template.backends.jinja2.Jinja2

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

  • DIRS defines a list of directories where the engine should look for template source files, in search order.
  • APP_DIRS tells whether the engine should look for templates inside installed applications. 每个后端都为其模板应存储在其中的应用程序内的子目录定义一个常规名称。

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

OPTIONS contains backend-specific settings.

用法¶ T0>

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

get_templatetemplate_nameusing = None[source]

该函数使用给定名称加载模板并返回一个Template对象。

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

get_template() tries each template engine in order until one succeeds. 如果无法找到模板,则会引发TemplateDoesNotExist 如果找到模板但包含无效语法,则会引发TemplateSyntaxError

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

If you want to restrict the search to a particular template engine, pass the engine’s NAME in the using argument.

select_templatetemplate_name_listusing = None[source]

select_template() is just like get_template(), except it takes a list of template names. 它按顺序尝试每个名称并返回存在的第一个模板。

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

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

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

后端
发生异常的模板后端实例。
试着
查找模板时尝试的来源列表。 它被格式化为包含(原始, 状态)的元组列表,其中originorigin-like对象和status是一个字符串,其原因是找不到模板。
尝试加载模板时引发的中间TemplateDoesNotExist异常列表。 这被诸如get_template()之类的函数使用,该函数尝试从多个引擎加载给定的模板。
例外 TemplateSyntaxError(msg)[source]

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

Template objects returned by get_template() and select_template() must provide a render() method with the following signature:

模板。rendercontext = Nonerequest = None

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

如果提供context,它必须是dict 如果没有提供,引擎将使用空的上下文呈现模板。

如果提供request,它必须是HttpRequest 然后引擎必须在模板中使用它以及CSRF令牌。 这是如何实现的到每个后端。

这是一个搜索算法的例子。 For this example the TEMPLATES setting is:

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

If you call get_template('story_detail.html'), here are the files Django will look for, in order:

  • /home/html/example.com/story_detail.html'django'引擎)
  • /home/html/default/story_detail.html'django'引擎)
  • /home/html/jinja2/story_detail.html'jinja2'引擎)

If you call select_template(['story_253_detail.html', 'story_detail.html']), here’s what Django will look for:

  • /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' % t2 > 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() loads a template like get_template() and calls its render() method immediately. 它采取以下参数。

TEMPLATE_NAME
要加载和渲染的模板的名称。 如果是模板名称列表,Django使用select_template()来代替get_template()来查找模板。
上下文
dict用作模板的渲染上下文。
请求
可选的HttpRequest将在模板的呈现过程中可用。
运用
一个可选的模板引擎NAME 搜索模板将被限制在该引擎。

用法示例:

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

See also the render() shortcut which calls render_to_string() and feeds the result into an HttpResponse suitable for returning from a view.

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

发动机 T0> ¶ T1>

模板引擎可以在django.template.engines中找到:

from django.template import engines

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

The lookup key — 'django' in this example — is the engine’s NAME.

内置后端

DjangoTemplates[source]

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

When APP_DIRS is True, DjangoTemplates engines look for templates in the templates subdirectory of installed applications. 这个通用名称保持向后兼容。

DjangoTemplates engines accept the following OPTIONS:

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

    它默认为True

    警告

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

  • 'context_processors':当模板被请求渲染时,用于填充上下文的可调用Python路径的点列表。 这些可调用对象将请求对象作为参数,并返回要合并到上下文中的dict个项目。

    它默认为一个空的列表。

    请参阅RequestContext了解更多信息。

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

    它默认为DEBUG设置的值。

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

    缺省值取决于DIRSAPP_DIRS的值。

    有关详细信息,请参见Loader types

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

    它默认为一个空字符串。

    有关详细信息,请参阅How invalid variables are handled

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

    它默认为FILE_CHARSET的值。

  • 'libraries':模板标签模块的标签和点状Python路径字典,用于注册模板引擎。 这可以用来添加新的库或为现有的库提供替代标签。 例如:

    OPTIONS={
        'libraries': {
            'myapp_tags': 'path.to.myapp.tags',
            'admin.urls': 'django.contrib.admin.templatetags.admin_urls',
        },
    }
    

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

  • 'builtins':要添加到built-ins的模板标记模块的虚线Python路径列表。 例如:

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

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

Jinja2[source]

需要安装Jinja2

$ 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 engines also accept the following OPTIONS:

  • 'context_processors':当模板被请求渲染时,用于填充上下文的可调用Python路径的点列表。 这些可调用对象将请求对象作为参数,并返回要合并到上下文中的dict个项目。

    它默认为一个空的列表。

    不鼓励使用带有Jinja2模板的上下文处理器。

    上下文处理器在Django模板中很有用,因为Django模板不支持使用参数调用函数。 由于Jinja2没有这个限制,建议使用下面描述的jinja2.Environment将可用作上下文处理器的函数放在模板可用的全局变量中。 然后您可以在模板中调用该函数:

    {{ function(request) }}
    

    一些Django模板上下文处理器返回一个固定值。 对于Jinja2模板,这个间接层不是必需的,因为您可以直接在jinja2.Environment中添加常量。

    为Jinja2添加上下文处理器的原始用例包括:

    • 根据请求进行昂贵的计算。
    • 需要每个模板的结果。
    • 在每个模板中多次使用结果。

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

Django 1.11新增功能:

添加了'context_processors'选项。

有目的地将默认配置保持在最低限度。 If a template is rendered with a request (e.g. when using render()), the Jinja2 backend adds the globals request, csrf_input, and csrf_token to the context. 除此之外,这个后端不会创建一个Django风格的环境。 它不知道Django过滤器和标签。 为了使用特定于Django的API,您必须将它们配置到环境中。

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

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支持在模板中传递参数给可调用对象,因此只需调用Jinja2模板中的函数即可实现Django模板中需要模板标签或过滤器的许多功能,如上例所示。 Jinja2的全局命名空间不需要模板上下文处理器。 Django模板语言没有相当于Jinja2的测试。

自定义后端

以下是如何实现自定义模板后端以使用其他模板系统。 模板后端是继承django.template.backends.base.BaseEngine的类。 它必须实现get_template()和可选的from_string() Here’s an example for a fictional foobar template library:

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().__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:

    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

自定义引擎的调试集成

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

模板postmortem

当发生TemplateDoesNotExist时,将显示该事件。 它列出了试图查找给定模板时使用的模板引擎和加载器。 例如,如果配置了两个Django引擎,那么postmortem将显示如下:

../_images/postmortem.png

自定义引擎可以在引发TemplateDoesNotExist时通过传递backendtried参数来填充事件。 使用postmortem should specify an origin

上下文行信息

如果在模板解析或渲染过程中发生错误,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对象。 这使调试信息能够显示在template postmortem以及第三方库中,如Django Debug Toolbar

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

  • 'name':模板的完整路径。
  • 'template_name':传递给模板加载方法的模板的相对路径。
  • 'loader_name':标识用于加载模板的函数或类的可选字符串,例如django.template.loaders.filesystem.Loader

Django模板语言

语法¶ T0>

关于本节

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

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

模板使用上下文呈现。 渲染用它们在上下文中查找的值替换变量,并执行标签。 其他一切都按原样输出。

Django模板语言的语法涉及四个构造。

变量¶ T0>

一个变量从上下文中输出一个值,这是一个字典型的对象映射键值。

变量由{{}}包围,如下所示:

My first name is {{ first_name }}. My last name is {{ last_name }}.

与上下文 {'名字': '约翰', '姓': “李四”},这个模板呈现给:

My first name is John. My last name is Doe.

字典查找,属性查找和列表索引查找用点符号实现:

{{ my_dict.key }}
{{ my_object.attribute }}
{{ my_list.0 }}

如果一个变量解析为一个可调用的,模板系统将调用它没有参数,并使用它的结果,而不是可调用的。

标记¶ T0>

标签在渲染过程中提供任意的逻辑。

这个定义是故意模糊的。 例如,标签可以输出内容,用作例如控制结构。 “if”语句或“for”循环,从数据库中获取内容,甚至可以访问其他模板标签。

标签由{%%}包围,如下所示:

{% csrf_token %}

大多数标签接受参数:

{% cycle 'odd' 'even' %}

一些标签需要开始和结束标签:

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

可以使用reference of built-in tags以及写入自定义标签的instructions for writing custom tags

过滤器¶ T0>

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

他们看起来像这样:

{{ django|title }}

与上下文 { 'django的': “在 卷筒纸 骨架 对于 完美主义者 最后期限},这个模板呈现给:

The Web Framework For Perfectionists With Deadlines

一些过滤器采取一个参数:

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

可以使用reference of built-in filters以及instructions for writing custom filters

注释¶ T0>

评论看起来像这样:

{# this won't be rendered #}

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

部件¶ T0>

关于本节

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

发动机¶ T0>

django.template.Engine encapsulates an instance of the Django template system. 直接实例化Engine的主要原因是在Django项目之外使用Django模板语言。

django.template.backends.django.DjangoTemplates is a thin wrapper adapting django.template.Engine to Django’s template backend API.

模板¶ T0>

django.template.Template represents a compiled template. 模板是通过Engine.get_template()Engine.from_string()

同样,django.template.backends.django.Template是一个将django.template.Template调整为通用模板API的薄包装器。

上下文¶ T0>

django.template.Context holds some metadata in addition to the context data. 它被传递给Template.render()来渲染一个模板。

django.template.RequestContext is a subclass of Context that stores the current HttpRequest and runs template context processors.

通用的API没有相同的概念。 上下文数据在普通的dict中传递,如果需要的话,当前的HttpRequest被单独传递。

装载机¶ T0>

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

Django提供了几个built-in template loaders并支持custom template loaders

上下文处理器

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

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

Django提供了很多built-in context processors 实现一个自定义的上下文处理器就像定义一个函数一样简单。