1,用{{}}包围的是变量,如{{person_name}},
2,用{%%}包围的是块标签,如{%if ordered_warranty%}
块标签的含义很丰富,它告诉模板系统做一些事情
在这个例子模板中包含两个块标签:for标签表现为一个简单的循环结构,让你按顺序遍历每条数据
if标签则表现为逻辑的if语句
在这里,上面的标签检查ordered_warranty变量的值是否为True
如果是True,模板系统会显示{%if ordered_warranty%}和{%endif%}之间的内容
否则,模板系统不会显示这些内容
模板系统也支持{%else%}等其它逻辑语句
3,上面还有一个过滤器的例子,过滤器是改变变量显示的方式
上面的例子中{{ship_date|date:"F j, Y"}}把ship_date变量传递给过滤器
并给date过滤器传递了一个参数“F j, Y”,date过滤器以给定参数的形式格式化日期
类似于Unix,过滤器使用管道字符“|”
Django模板支持多种内建的块标签,并且你可以写你自己的标签
网站模板的设计,一般的,我们做网站有一些通用的部分,比如 导航,底部,访问统计代码等。合理的规划模板往往会减少工作量,同时也使得罗乱、难以阅读的静态页面布局变得优雅。
假设,我们的网站主页面除了正文是由导航条,低栏,统计栏构成。也就是nav.html,bottom.html,tongji.html。
在构建页面的时候,可以写一个base.html来包含(include)这些通用文件,如下:
{% block title %}默认标题{% endblock %}
{% include 'nav.html' %}
{% block content %}
{% endblock %}
{% include 'bottom.html' %}
{% include 'tongji.html' %}
在这里,所有的include都是引入通用文件,而block都是定义默认模块,其他继承base.html的页面,都可以在自己的页面中重新定义这些模块,达到覆盖替换的作用。
比如我们设计一个主页面index.html,继承自base.html,同时替换base.html中的title和content两个模块。以下是index.html文件的内容:
{% extends 'base.html' %}
{% block title %}欢迎光临首页{% endblock %}
{% block content %}
{% include 'ad.html' %}
这里是首页,欢迎光临
{% endblock %}
运行这个页面,你就会发现,原有的base.html中的模块被替换掉了。
注意 {%block %}中的标签是可以自定义的,不一定要content,title,但是要简单明了
if/else
{% if %}标签计算一个变量值,如果是“true”,即它存在、不为空并且不是false的boolean值
系统则会显示{% if %}和{% endif %}间的所有内容:
{% if today_is_weekend %}
Welcome to the weekend!
{%else %}
Get back to work.
{% endif %}
{% if %}标签接受and,or或者not来测试多个变量值或者否定一个给定的变量,例如:
{% if athlete_list and coach_list %}
Both athletes and coaches are available.
{% endif %}
{%if not athlete_list %}
There are no athletes.
{% endif %}
{%if athlete_list or coach_list %}
There are some athletes or some coaches.
{% endif %}
{%if not athlete_list or coach_list %}
There are no athletes or there are some coaches.
{% endif %}
{%if athlete_list and not coach_list %}
There are some athletes and absolutely no coaches.
{% endif %}
{% if %}标签不允许同一标签里同时出现and和or,否则逻辑容易产生歧义,例如下面的标签是不合法的:
{% if athlete_list and coach_list or cheerleader_list %}
如果你想结合and和or来做高级逻辑,只需使用嵌套的{% if %}标签即可:
{% if athlete_list %}
{%if coach_list or cheerleader_list %}
We have athletes, and either coaches or cheerleaders!
{% endif %}
{% endif %}
多次使用同一个逻辑符号是合法的:
{% if athlete_list or coach_list or parent_list or teacher_list %}
没有{% elif %}标签,使用嵌套的{% if %}标签可以做到同样的事情:
{% if athlete_list %}
Here are the athletes: {{ athlete_list }}.
{%else %}
No athletes are available.
{%if coach_list %}
Here are the coaches: {{ coach_list }}.
{% endif %}
{% endif %}
确认使用{% endif %}来关闭{% if %}标签,否则Django触发TemplateSyntaxError
for
{% for %}标签允许你按顺序遍历一个序列中的各个元素
Python的for语句语法为for X in Y,X是用来遍历Y的变量
每次循环模板系统都会渲染{% for %}和{% endfor %}之间的所有内容
例如,显示给定athlete_list变量来显示athlete列表
{%for athlete in athlete_list %}
{% endfor %}
在标签里添加reversed来反序循环列表:
{% for athlete in athlete_list reversed %}
...
{% endfor %}
{%for %}标签可以嵌套:
{%for country in countries %}
{{ country.name }}
{%for city in country.city_list %}
{% endfor %}
{% endfor %}
系统不支持中断循环,如果你想这样,你可以改变你想遍历的变量来使得变量只包含你想遍历的值
类似的,系统也不支持continue语句,本章后面的“哲学和限制”会解释设计的原则
{% for %}标签内置了一个forloop模板变量,这个变量含有一些属性可以提供给你一些关于循环的信息
1,forloop.counter表示循环的次数,它从1开始计数,第一次循环设为1,例如:
{% for item in todo_list %}
{{ forloop.counter }}: {{ item }}
{% endfor %}
2,forloop.counter0类似于forloop.counter,但它是从0开始计数,第一次循环设为0
3,forloop.revcounter表示循环中剩下的items数量,第一次循环时设为items总数,最后一次设为1
4,forloop.revcounter0类似于forloop.revcounter,但它是表示的数量少一个,即最后一次循环时设为0
5,forloop.first当第一次循环时值为True,在特别情况下很有用:
{% for object in objects %}
{%if forloop.first %}{% else %}
{{ object }}
{% endfor %}
6,forloop.last当最后一次循环时值为True
{% for link in links %}{{ link }}{% if not forloop.last %} | {% endif %}{% endfor %}
7,forloop.parentloop在嵌套循环中表示父循环的forloop:
{% for country in countries %}
{%for city in country.city_list %}
Country #{{ forloop.parentloop.counter }}
City #{{ forloop.counter }}
{{ city }}
{% endfor %}
{% endfor %}
富有魔力的forloop变量只能在循环中得到,当模板解析器到达{% endfor %}时forloop就消失了
如果你的模板context已经包含一个叫forloop的变量,Django会用{% for %}标签替代它
Django会在for标签的块中覆盖你定义的forloop变量的值
在其他非循环的地方,你的forloop变量仍然可用
我们建议模板变量不要使用forloop,如果你需要这样做来访问你自定义的forloop,你可以使用forloop.parentloop
ifequal/ifnotequal
Django模板系统并不是一个严格意义上的编程语言,所以它并不允许我们执行Python语句
(我们会在‘哲学和限制‘一节详细讨论)。
然而在模板语言里比较两个值并且在他们一致的时候显示一些内容,确实是一个在常见不过的需求了——所以Django提供了ifequal标签。
{% ifequal %}比较两个值,如果相等,则显示{% ifequal %}和{% endifequal %}之间的所有内容:
{% ifequal user currentuser %}
Welcome!
{% endifequal %}
参数可以是硬编码的string,单引号和双引号均可,下面的代码是合法的:
{% ifequal section 'sitenews' %}
Site News
{% endifequal %}
{% ifequal section"community" %}
Community
{% endifequal %}
和{% if %}一样,{% ifequal %}标签支持{% else %}
{% ifequal section 'sitenews' %}
Site News
{%else %}
No News Here
{% endifequal %}
其它的模板变量,strings,integers和小数都可以作为{% ifequal %}的参数:
{% ifequal variable 1 %}
{% ifequal variable1.23 %}
{% ifequal variable'foo' %}
{% ifequal variable"foo" %}
其它的Python类型,如字典、列表或booleans不能硬编码在{% ifequal %}里面,下面是不合法的:
{% ifequal variable True %}
{% ifequal variable [1, 2, 3,]%}
{% ifequal variable {'key': 'value'} %
如果你需要测试某个变量是true或false,用{% if %}即可
注释
和HTML或编程语言如Python一样,Django模板语言允许注释{# #},如:
{# This is a comment #}
模板渲染时注释不会输出,一个注释不能分成多行
下面的模板渲染时会和模板中的内容一样,注释标签不会解析成注释
This is a {# comment goes here
and spans another line #}
test.
过滤器
本章前面提到,模板过滤器是变量显示前转换它们的值的方式,看起来像下面这样:
{{ name|lower }}
这将显示通过lower过滤器过滤后{{ name }}变量的值,它将文本转换成小写
使用(|)管道来申请一个过滤器
过滤器可以串成链,即一个过滤器的结果可以传向下一个
下面是escape文本内容然后把换行转换成p标签的习惯用法:
{{ my_text|escape|linebreaks }}
有些过滤器需要参数,需要参数的过滤器的样子:
{{ bio|truncatewords:"30" }}
这将显示bio标量的前30个字,过滤器参数一直使用双引号
下面是一些最重要的过滤器:
1,addslashed,在任何后斜线,单引号,双引号前添加一个后斜线
当你把一些文本输出到一个JavaScript字符串时这会十分有用
2,date,根据一个格式化string参数来格式化date或datetime对象,例如:
{{ pub_date|date:"F j, Y" }}
格式化string会在附录6定义
3,escape,避免给定的string里出现and符,引号,尖括号
当你处理用户提交的数据和确认合法的XML和XHTML数据时这将很有用
escape将作如下的一些转换:
Converts & to &
Converts < to <
Converts > to >
Converts "(双引号) to "
Converts '(单引号) to '
4,length,返回值的长度,你可以在一个list或string上做此操作
或者在任何知道怎样决定自己的长度的Python对象上做此操作(即有一个__len__()方法的对象)
哲学和限制
现在我们对于Django地模板系统有了一个感性的认识,下面我们将指出一些有意为之的限制和它工作的哲学
不像其他Web程序组件,程序员对模板系统的意见非常不一致
一个很有意思的事实:Python至少拥有数十个——如果没有上百个——的开源模板语言实现,而且看来每一个都是因为其创造者认为现有的模板不能满足他们的要求。
(事实上,据说写一个自己的模板系统是已经成了Python开发者必经的仪式了。如果你还没有写过自己的模板系统,试试看吧,真是很有意思。)
所以,Django的第一个哲学就是Django不强求你使用它的模板语言
Django的目标是提供一个full-stack框架,提供所有必须的web开发模块进行高效开发
很多时候,使用Django的模板系统很方便,但不强求你使用它
下面的“在视图中使用模板”一节我们会看到在Django中使用另一套模板语言,它同样简单易用
但我们仍强烈需要Django的模板语言的工作方式,模板系统深植于World Online和Django发明者的
Web开发方式中,下面是其中一些哲学:
1,业务逻辑应该和呈现逻辑分离
模板系统应该只负责控制显示和显示相关的逻辑我们视模板为一种控制显示和显示相关逻辑的工具,仅此而已。模板系统的功能就止于此。
基于这个原因,Django模板无法直接调用Python代码。在Django模板里,所有的程序设计活动都止于对标签的使用。
虽然你可以自定义模板标签来做任意的事情,但Django自己的模板标签不允许执行Python代码。
2,语法应该和HTML/XML解耦
Django的模板系统采用非HTML格式,如普通的文本,有些其它的模板语言是基于XML的
XML的格式容易输错,并且XML的模板解析速度也容易变得很慢而难以接受
3,页面设计者被假定为熟悉HTML代码
Django模板系统没有设计成可以在Dreamweaver等WYSISYG编辑器中显示良好
这类编辑器有很多限制,Django希望模板作者直接编辑HTML时感到舒适
4,页面设计者被假定为不是Python程序员
模板系统的作者意识到大部分Web页面的模板是页面设计者写的而不是Python程序员写的
他们不具备Python知识,但Django也允许模板用Python来写,它提供了一种直接编写Python代码
来扩展模板系统的方法(第10章会介绍更多)
5,目标不是发明一种编程语言
目标只是提供足够的编程功能,如分支和循环等决定呈现相关的逻辑用
由于上述的设计哲学,Django模板系统产生如下限制:
1,模板不能设置和改变变量的值
可以通过自定义模板标签来达到这个目标(I参看第10章),但是内置Django模板标签不允许这样做
2,模板不能调用原生Python代码
但是也可以通过自定义标签来做这件事情