每一个Web框架都需要一种很便利的方法用于动态生成HTML页面。 最常见的做法是使用模板。
模板包含所需HTML页面的静态部分,以及一些特殊的模版语法,用于将动态内容插入静态部分。
说白了,模板层就是如何往HTML文件中填入动态内容的系统。
Django可以配置一个或多个模板引擎(语言),也可以不用引擎。
Django自带一个称为DTL(Django Template Language )的模板语言,以及另外一种流行的Jinja2语言(需要提前安装,pip install Jinja2)。
Django为加载和渲染模板定义了一套标准的API,与具体的后台无关。加载指的是,根据给定的模版名称找到的模板然后预处理,通常会将它编译好放在内存中。渲染则表示,使用Context数据对模板插值并返回生成的字符串。
DTL作为Django原生的模板系统,一直到Django1.8,都是唯一的内置模版系统,可能你对它有些意见,但是它仍然是一个优秀的模版库。如果没有特别重要的理由,需要选择另外一种模版系统的话,建议坚持使用DTL,特别是在编写可插拔的应用并打算发布其模板的时候。Django很多内部组件都使用了DTL,例如django.contrib.admin
,如果你不想让它们罢工,或者花费大力气进行修改,不要放弃DTL。
模板引擎通过settings中的TEMPLATES
设置来配置。这是一个列表,与引擎一一对应,每个元素都是一个引擎配置字典。由startproject命令生成的settings.py
会自定定义如下的值:
TEMPLATES = [ { 'BACKEND': 'django.template.backends.django.DjangoTemplates', 'DIRS': [], 'APP_DIRS': True, 'OPTIONS': { # ... some options here ... }, }, ]
BACKEND:后端。内置的后端有django.template.backends.django.DjangoTemplates
和django.template.backends.jinja2.Jinja2
。
OPTIONS中包含了具体的后端设置。
由于绝大多数引擎都是从文件加载模板的,所以每种模板引擎都包含两项通用设置:
每种模板引擎后端都定义了一个惯用的名称作为应用内部存放模板的子目录名称。(例如Django为它自己的模板引擎指定的是 ‘templates’,为jinja2指定的名字是‘jinja2’)。尤其是,django允许你有多个模板引擎后端实例,且每个实例有不同的配置选项。 在这种情况下你必须为每个配置指定一个唯一的NAME .
DTL引擎的OPTIONS配置项中接受以下参数:
context_processors
: 以"."为分隔符的Python调用路径的列表。默认是个空列表。APP_DIRS
的值。string_if_invalid
:非法变量时输出的字符串。默认为空字符串。file_charset
:用于读取磁盘上的模板文件的字符集编码。默认为FILE_CHARSET
的值。django.template.loader
中定义了两个函数以加载模板。
get_template(template_name,using = None)[source]
该函数使用给定的名称查找和加载模板,并返回一个Template对象。
模板的查找和加载机制取决于每种后端引擎和配置,如果想使用指定的模板引擎进行查找,请将模板引擎的NAME赋给get_template
的using参数。
select_template(template_name_list,using = None)[source]
和get_template()相似, 只不过它使用包含模板名称的列表作为参数。
由select_template()
和get_template()
返回的Template对象都必须提供一个render()方法,如下所示:
Template.render(context=None, request=None)
通过给定的context对该模板进行渲染。
如果提供了context,那么它必须是一个dict对象。如果要提供request参数 ,必须使用HttpRequest对象。
针对下面的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将按以下顺序查找story_detail.html
:
/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查找到任何一个匹配的模板后便停止搜寻,所以这是个类似url搜索的短路操作!
强调:前面我们介绍过,建议在每个APP的的模版子目录下都建立一个子目录来唯一对应这个APP。这样做可以增强你的APP的可用性。 将所有的模版文件放在根模版目录下会引发混淆。
要在一个子目录内加载模板,像下面这样:
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()
方法。 它需要以下参数。
用法示例:
from django.template.loader import render_to_string rendered = render_to_string('my_template.html', {'foo': 'bar'})
以后,如果没有特别强调,都是针对DTL引擎。
Django模板语言的语法包括四种结构。
变量的值来自context中的数据字典, 类似于字典对象的keys到values的映射关系。
变量是被}}
和{{
括起来的部分,例如:
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 }}
模版语言中的标签类似Python中的函数,功能多样,使用灵活。可以输出内容、控制结构,甚至可以访问其他的模板标签。
标签是由%}
和{%
来定义的,例如:
{% csrf_token %} # csrf令牌标签
大部分标签都接受参数:
{% cycle 'odd' 'even' %} # 循环使用'odd'和'even'
部分标签需要使用起始和闭合标签,典型代表为for循环标签和if判断标签:
{% 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" }} # 按指定的格式"Y-m-d",显示日期
模版语言的注释看起来像这样:
{# this won't be rendered #} # 单行注释
{% comment %}
标签提供多行注释功能。