作为Web 框架,Django 需要一种很便利的方法以动态地生成HTML。最常见的做法是使用模板。模板包含所需HTML 输出的静态部分,以及一些特殊的语法,描述如何将动态内容插入。
Django 项目可以配置一个或多个模板引擎(甚至是零,如果你不需要使用模板)。Django 的模板系统自带内建的后台 —— 称为Django 模板语言(DTL),以及另外一种流行的Jinja2。其他的模板语言的后端,可查找第三方库。
模板引擎通过TEMPLATES 设置来配置。它是一个设置选项列表,与引擎一一对应。默认的值为空。由startproject 命令生成的settings.py 定义了一些有用的值:
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [],
'APP_DIRS': True,
'OPTIONS': {
# ... some options here ...
},
},
]
由于绝大多数引擎都是从文件加载模板的,所以每种模板引擎都包含两项通用设置:
django.template.loader 定义了两个函数以加载模板。
get_template(template_name[, dirs][, using])
该函数使用给定的名称加载模板并返回一个Template 对象.
由get_template()
和select_template()
返回的Template 对象必须要有一个render()方法,协议如下:
Template.render(context=None, request=None)
通过给定的 context 对该模板进行渲染。
关于搜索算法的例子。该例子下 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',
],
},
]
另外,为了减少加载模板、渲染模板等重复工作,django提供了处理这些工作的快捷函数。
render_to_string(template_name[, context][, context_instance][, request][, using])
render_to_string() 会像 get_template()一样加载模板并立即调用 render() 方法。 它需要以下参数:
select_template()
来寻找模板位置。设置BACKEND 为 ‘django.template.backends.django.DjangoTemplates’ 来配置Django模板引擎。
当 APP_DIRS 为 True 时, DjangoTemplates 引擎会在已安装应用的 templates 子目录中查找模板文件。 这个通用名称是保持向后兼容的。
DjangoTemplates 引擎 OPTIONS 配置项中接受以下参数:
如果您有过编程背景,或者您使用过一些在HTML中直接混入程序代码的语言,那么现在您需要记住,Django的模版系统并不是简单的将Python嵌入到HTML中。 设计决定了:模版系统致力于表达外观,而不是程序逻辑。
模版是纯文本文件。它可以产生任何基于文本的的格式(HTML,XML,CSV等等)。
模版包括在使用时会被值替换掉的 变量,和控制模版逻辑的 标签。
下面是一个小模版,它说明了一些基本的元素。后面的文档中会解释每个元素。
{% extends "base_generic.html" %}
{% block title %}{{ section.title }}{% endblock %}
{% block content %}
<h1>{{ section.title }}h1>
{% for story in story_list %}
<h2>
<a href="{{ story.get_absolute_url }}">
{{ story.headline|upper }}
a>
h2>
<p>{{ story.tease|truncatewords:"100" }}p>
{% endfor %}
{% endblock %}
为什么要使用基于文本的模版,而不是基于XML的(比如Zope的TAL)呢?我们希望Django的模版语言可以用在更多的地方,而不仅仅是XML/HTML模版。在线上世界,我们在email、Javascript和CSV中使用它。你可以在任何基于文本的格式中使用这个模版语言。
变量看起来就像是这样: {{ variable }}。
点号(.)用来访问变量的属性。从技术上来说,当模版系统遇到点(“.”),它将以这样的顺序查询:
过滤器看起来是这样的:{{ name|lower }}。这将在变量 {{ name }} 被过滤器 lower 过滤后再显示它的值,该过滤器将文本转换成小写。使用管道符号 (|)来应用过滤器。
过滤器参数包含空格的话,必须被引号包起来;例如,使用逗号和空格去连接一个列表中的元素,你需要使用 {{ list|join:”, ” }}。
常用的模版过滤器:
{{ value|default:"nothing" }}
{{ value|length }}
{{ value|filesizeformat }}
标签看起来像是这样的: {% tag %}。标签比变量复杂得多:有些用于在输出中创建文本,有些用于控制循环或逻辑,有些用于加载外部信息到模板中供以后的变量使用。
有些标签需要开始标签和结束标签(例如{% tag %} … tag contents … {% endtag %})。
常用的标签:
要注释模版中一行的部分内容,使用注释语法 {# #}.
例如,这个模版将被渲染为 ‘hello’:{# greeting #}hello
Django模版引擎中最强大也是最复杂的部分就是模版继承了。模版继承可以让您创建一个基本的“骨架”模版,它包含您站点中的全部元素,并且可以定义能够被子模版覆盖的 blocks 。
您可以根据需要使用多级继承。使用继承的一个常用方式是类似下面的三级结构:
base_SECTIONNAME.html
模版。例如, base_news.html
, base_sports.html
。这些模版都继承自 base.html
,并且包含了每部分特有的样式和设计。使用继承的一些提示:
当从模版中生成HTML时,总会有这样一个风险:值可能会包含影响HTML最终呈现的字符。显然,用户提交的数据都被不应该被盲目的信任,并且被直接插入到你的网页中,因为一个怀有恶意的用户可能会使用这样的漏洞来做一些可能的坏事。这种类型的安全问题被叫做 跨站脚本(Cross Site Scripting) (XSS) 攻击。
默认情况下,Django 中的每个模板会自动转义每个变量的输出。明确地说,下面五个字符被转义:
然而你为什么想要关闭它呢?由于有时,模板变量含有一些你打算渲染成原始HTML的数据,你并不想转义这些内容。例如,你可能会在数据库中储存一些HTML代码,并且直接在模板中嵌入它们。或者,你可能使用Django的模板系统来生成不是HTML的文本 – 比如邮件信息。
提供的几种方法:
his will not be escaped: {{ data|safe }}
{% autoescape off %}Hello {{ name }}{% endautoescape %}
大多数对象上的方法调用同样可用于模板中。这意味着模板能够访问到的不仅仅是类属性(比如字段名称)和视图中传入的变量。例如,Django ORM提供了“entry_set” 语法用于查找关联到外键的对象集合。所以,如果模型“comment” 有一个外键关联到模型“task” ,你可以根据task 遍历其所有的comments,像这样:
{% for comment in task.comment_set.all %}
{{ comment }}
{% endfor %}
某些应用提供自定义的标签和过滤器库。要在模板中访问它们,确保应用已经在INSTALLED_APPS 中(在这个例子中我们添加了’django.contrib.humanize’),之后在模板中使用load标签:
{% load humanize %}
{{ 45000|intcomma }}
当你加载一个自定义标签或过滤器库时,标签或过滤器只在当前模板中有效 – 并不是带有模板继承关系的任何父模板或者子模版中都有效。
例如,如果一个模板foo.html带有{% load humanize %},子模版(例如,带有{% extends “foo.html” %})中不能 访问humanize模板标签和过滤器。子模版需要添加自己的 {% load humanize %}。
这个特性是出于保持可维护性和逻辑性的目的。