Django 2.1.3 文档-模板-概述

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

Django项目可以配置一个或多个模板引擎(或者不使用模板)。Django后端内置一个自己的模板系统,创造性地称为Django template language(DTL)和一个流行的替代品JINJA2。后端也可以使用第三方提供其他可用的模板语言。

Django定义了一个标准的API,用于加载和渲染模板,而不用考虑后端的模板系统。加载包括查找给定标识符的模板并对其进行预处理,通常将其编译的结果保存在内存中。渲染工具将上下文数据插入模板并返回结果字符串。

Django 模板语言 是Django自己的模板系统。直到Django 1.8,它是唯一可用的内置选项。这是一个很好的模板库,即使它是相当僵硬和使用时带有它自己特质。如果您没有紧迫的理由需要去选择另一个后端,则应该使用DTL,特别是如果您正在编写可插入的应用程序并打算分发模板。在 Django’s contrib apps 中的有些模板,比如 django.contrib.admin ,使用DTL。

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

警告

模板系统使用不可信的模板作者的模板是不安全的。例如,一个站点不应该允许它的用户提供他们自己的模板,因为模板作者可以做一些事情,比如执行XSS攻击和拿到包含敏感信息的模板变量的访问权。

1. 模板引擎的支持

1.1 配置

模板引擎在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

扫描二维码关注公众号,回复: 4332890 查看本文章

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

  • DIRS 定义了模板源文件的目录列表,引擎按搜索顺序查找。
  • APP_DIRS告诉引擎是否应该在已安装的应用程序中查找模板。每个后端都定义应用程序中应存储其模板的子目录的常规名称。

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

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

1.2 用法

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

(1)get_template(template_name,using = None)源码
此函数使用给定名称加载模板并返回一个 Template对象。

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

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

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

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

(2)select_template(template_name_list,using = None)source
select_template()就像是get_template(),除了它采用模板名称列表。它按顺序尝试每个名称并返回存在的第一个模板。

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

(1)TemplateDoesNotExist(msg,tries = None,backend = None,chain = None)source
无法找到模板时引发此异常。它接受以下可选参数,用于在调试页面上填充 模板postmortem

  • backend
    发生异常的模板后端实例。
  • tried
    查找模板时尝试的源列表。这被格式化为包含(origin, status)元组的列表,其中origin是origin-like对象,并且status是一个字符串,其中包含未找到模板的原因。
  • chain
    尝试加载模板时引发的TemplateDoesNotExist异常列表。这由get_template()尝试从多个引擎加载给定模板的函数使用。

(2)TemplateSyntaxError(msg)source
找到模板但包含错误时会引发此异常。

(3)Template.render(context = None,request = None)
使用给定的上下文呈现此模板。

通过get_template()和select_template() 返回的Template对象必须提供render()方法。

如果提供context,它必须是字典类型。如果未提供,则引擎将使用空上下文呈现模板。

如果提供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’ engine)
    /home/html/default/story_detail.html(‘django’ engine)
    /home/html/jinja2/story_detail.html(‘jinja2’ engine)

如果你调用select_template(['story_253_detail.html', 'story_detail.html']),这是Django会寻找的:

  • /home/html/example.com/story_253_detail.html(‘django’ engine)
    /home/html/default/story_253_detail.html(‘django’ engine)
    /home/html/jinja2/story_253_detail.html(‘jinja2’ engine)
    /home/html/example.com/story_detail.html(‘django’ engine)
    /home/html/default/story_detail.html(‘django’ engine)
    /home/html/jinja2/story_detail.html(‘jinja2’ engine)

当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’ engine)
    /home/html/default/news/story_detail.html(‘django’ engine)
    /home/html/jinja2/news/story_detail.html(‘jinja2’ engine)

此外,为了减少加载和渲染模板的重复性,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
    一个字典用作模板的渲染上下文。
  • 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。


1.3 内置后端

1.3.1 DjangoTemplates(默认后端)

class DjangoTemplates 源代码
设置BACKEND'django.template.backends.django.DjangoTemplates',以配置Django模板引擎。

如果APP_DIRS是True,DjangoTemplates 引擎在应用程序的templates的子目录内寻找模板文件。保留此通用名称是为了向后兼容。

DjangoTemplates引擎接受以下OPTIONS

  • 'autoescape':一个控制是否启用HTML自动转义的布尔值。
    它默认为True。
    警告 --> 只有在渲染非HTML模板时才设置为False!

  • 'context_processors':用于在使用请求呈现模板时用于填充上下文的可调整的python路径列表。这些可调用对象将请求对象作为其参数,并返回 一个字典而且整合到上下文中。
    默认为空列表。有关RequestContext更多信息。

  • 'debug':一个打开/关闭模板调试模式的布尔值。如果是 True,则错误页面将显示模板呈现期间引发的任何异常的详细报告。此报告包含模板的相关片段,并突出显示相应的行。
    它默认为settings.py文件中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 %}标签来加载库。
{% load static %}

  • 'builtins':要添加到内置函数的模板标记模块的虚拟Python路径列表。例如:
OPTIONS={
    'builtins': ['myapp.builtins'],
}

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

1.3.2 Jinja2

class Jinja2 源代码
需要安装Jinja2

 pip install Jinja2

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

如果APP_DIRS是True,Jinja2引擎寻找在安装应用程序的jinja2的子目录内的模板。

最重要的OPTIONS条目是'environment'。它是返回Jinja2环境的可调用的Python路径。它默认为'jinja2.Environment'。Django调用它并将其他选项作为关键字参数传递。此外,Django添加了与Jinja2不同的默认选项:

  • 'autoescape': True
  • 'loader':为DIRS和 APP_DIRS配置的加载器
  • 'auto_reload': settings.DEBUG
  • 'undefined'DebugUndefined if settings.DEBUG else Undefined

Jinja2引擎也接受以下OPTIONS:

'context_processors':用于在使用请求呈现模板时用于填充上下文的可调整的python路径列表。这些可调用对象将请求对象作为其参数,并返回 一个字典而且整合到上下文中。
默认为空列表。


不鼓励在Jinja2中使用context_processors。

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

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

为Jinja2添加context_processors的原始用法包括:

  • 根据请求进行耗时的计算。
  • 需要每个模板的结果。
  • 在每个模板中多次使用结果。
    除非满足所有这些条件,否则将函数传递给模板更简单,更符合Jinja2的设计。

有目的地将默认配置保持在最低限度。如果一个模板与一个请求呈现(例如,使用时render())时,Jinja2后端在上下问中添加全局request,csrf_input和 csrf_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支持将参数传递给模板中的可调用对象,因此可以通过调用Jinja2模板中的函数来实现许多需要Django模板中的模板标记或过滤器的功能,如上例所示。Jinja2的全局命名空间消除了对模板上下文处理器的需求。Django模板语言没有等价于Jinja2的测试。

1.3.3 自定义后端

以下是如何实现自定义模板后端以便使用其他模板系统。一个模板后端是一个继承自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().__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

1.4 自定义引擎的调试集成

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

1.4.1 Template postmortem

postmortem会同TemplateDoesNotExist一起出现。它列出了在尝试查找给定模板时使用的模板引擎和加载器。例如,如果配置了两个Django引擎,则postmortem将显示为:
在这里插入图片描述

自定义引擎可以通过在引发TemplateDoesNotExist时传递backendtried参数来填充时间。使用了postmortem的后端应该在模板对象上specify an origin

1.4.2 行的上下文信息

如果在模板解析或渲染过程中发生错误,Django可以显示错误发生的行。例如:
在这里插入图片描述
自定义引擎可以填充这些信息,通过在解析和渲染期间引发的异常上设置template_debug属性。此属性字典具有以下值:

键的属性 含义
‘name’ 发生异常的模板的名称。
‘message’ 异常消息
‘source_lines’ 行之前,之后和包括发生异常的行。这是针对上下文的,所以它不应该包含超过20行左右
‘line’ 发生异常的行。
‘before’ 引发错误的token之前的错误行上的内容
‘during’ 引发错误的token
‘after’ 引发错误的token后错误行上的内容
‘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,
}

1.4.3 Origin API和第三方集成

Django模板提供了一个Origin对象,通过template.origin属性。这使得调试信息可以显示在模板postmortem中,也可以显示在第三方库中,如Django Debug Toolbar

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

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

2.Django 模板语言

2.1 语法

关于本节
这是Django模板语言语法的概述。有关详情请参阅 语言的语法参考

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

使用上下文呈现模板。渲染将变量替换为其值,这些值在上下文中查找,并执行标记。其他所有内容都按原样输出。

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

2.1.1 变量

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

变量被{{}}包围:

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

如果变量解析为可调用的函数,则模板系统将调用它而不带参数,并使用其结果进行渲染。


译者实例
(1)在views.py中定义如下:

class Classval:
    def __init__(self):
        self.val = 10
        self.dicts ={"id":id(self),"val":self.val}
        self.lists = ["Classval",self.val]

    def getpow(self):
        return pow(self.val,3)

def index(request):
    cv = Classval()
    return render(request,'model_layer/index.html',locals())

(2)在model_layer/index.html中定义如下html内容:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
cv.val:{{ cv.val }}<hr>
cv.dicts.id:{{ cv.dicts.id }}<hr>
cv.dicts.val:{{ cv.dicts.val }}<hr>
cv.lists.0:{{ cv.lists.0 }}<hr>
cv.lists.1:{{ cv.lists.1 }}<hr>
cv.getpow:{{ cv.getpow }}<hr>
</body>
</html>

(3)输出结果
在这里插入图片描述

2.1.2 标签

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

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

标签被{%%}包围,比如:
{% csrf_token %}

大多数标签接受参数:
{% cycle 'odd' 'even' %}

有些标签需要开始和结束标签:
{% if user.is_authenticated %}Hello, {{ user.username }}.{% endif %}
译者提供了 内置标签 的参考以及编写自定义标签的说明。

2.1.1 过滤器

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

它们看起来像这样:
{{ django|title }}

在上下文中如果有此变量{'django': 'the web framework for perfectionists with deadlines'},此模板呈现为:

The Web Framework For Perfectionists With Deadlines
一些过滤器还接收参数:

{{ my_date|date:"Y-m-d" }}
译者提供了内置过滤器 的参考以及 编写自定义过滤器 的说明。

2.1.1 注释

两种注释:单行注释({# ... #})和多行注释{% comment %}...{% endcomment %}

{# hello 单行注释 #}

{% comment %}
多行注释1
多行注释2 
...
{% endcomment %}

2.2 组件

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

2.2.1 引擎

django.template.Engine 封装了Django模板系统的一个实例。Engine直接实例化的主要原因 是在Django项目之外使用Django模板语言。

django.template.backends.django.DjangoTemplates是一个适合Django模板后端API 的小型django.template.Engine包装器。

2.2.1 模板

django.template.Template表示已编译的模板。模板是用Engine.get_template()或Engine.from_string()来获得的。

同样,django.template.backends.django.Template是一个适合通用模板API 的小型django.template.Template包装器。

2.2.1 上下文

django.template.Context 除了上下文数据之外还包含一些元数据。它被传递给Template.render()渲染模板。

django.template.RequestContext是Context存储当前 HttpRequest和运行模板上下文处理器的子类 。

通用API没有相同的概念。上下文数据以普通方式传递,如果需要,可以分开传递字典和当前HttpRequest。

2.2.1 加载器

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

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

2.2.1 上下文处理器

上下文处理器是一个函数,接收当前 HttpRequest为参数并返回一个字典,字典里是要添加到呈现上下文的数据。

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

Django提供了许多内置的上下文处理器。实现自定义上下文处理器就像定义函数一样简单。


猜你喜欢

转载自blog.csdn.net/lengfengyuyu/article/details/84574927