一、if/else
{% if %} 标签检查(evaluate)一个变量,如果这个变量为真(即,变量存在,非空,不是布尔值假),系统会显示在 {% if %} 和 {% endif %} 之间的任何内容,例如:
{% if today_is_weekend %}
<p>Welcome to the weekend!</p>
{% endif %}
{% else %} 标签是可选的:
{% if today_is_weekend %}
<p>Welcome to the weekend!</p>
{% else %}
<p>Get back to work.</p>
{% endif %}
Python 的“真值”
在python中空的列表 ( [] ),tuple( () ),字典( {} ),字符串( '' ),零( 0 ),还有 None 对象,在逻辑判断中都为假,其他的情况都为真。
{% if %} 标签接受 and , or 或者 not 关键字来对多个变量做判断 ,或者对变量取反( 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. (OK, so writing English translations of Boolean logic sounds stupid; it's not our fault.) {% 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 %} <p>Here are the athletes: {{ athlete_list }}.</p> {% else %}
<p>No athletes are available.</p>
{% if coach_list %}
<p>Here are the coaches: {{ coach_list }}.</p>
{% endif %}
{% endif %}
一定要用 {% endif %} 关闭每一个 {% if %} 标签。否则Django会抛出 TemplateSyntaxError 。
二、for
{% for %} 允许我们在一个序列上迭代。与Python的 for 语句的情形类似,循环语法是 for X in Y ,Y是要迭代的序列而X是在每一个特定的循环中使用的变量名称。每一次循环中,模板系统会渲染在 {% for %} and {% endfor %} 中的所有内容。
例如,给定一个运动员列表 athlete_list 变量,我们可以使用下面的代码来显示这个列表:
<ul> {% for athlete in athlete_list %} <li>{{ athlete.name }}</li> {% endfor %} </ul>
给标签增加一个 reversed 使得该列表被反向迭代:
{% for athlete in athlete_list reversed %} ... {% endfor %}
可以嵌套使用 {% for %} 标签:
{% for country in countries %} <h1>{{ country.name }}</h1> <ul> {% for city in country.city_list %} <li>{{ city }}</li> {% endfor %} </ul> {% endfor %}
Django不支持退出循环操作。如果我们想退出循环,可以改变正在迭代的变量,让其仅仅包含需要迭代的项目。同理,Django也不支持continue语句,我们无法让当前迭代操作跳回到循环头部。(请参看本章稍后的理念和限制小节,了解下决定这个设计的背后原因){% for %} 标签在循环中设置了一个特殊的 forloop 模板变量。这个变量能提供一些当前循环进展的信息:
forloop.counter 总是一个表示当前循环的执行次数的整数计数器。这个计数器是从1开始的,所以在第一次循环时 forloop.counter 将会被设置为1。例子如下:
{% for item in todo_list %} <p>{{ forloop.counter }}: {{ item }}</p> {% endfor %}
forloop.counter0 类似于 forloop.counter ,但是它是从0计数的。第一次执行循环时这个变量会被设置为0。
forloop.revcounter 是表示循环中剩余项的整型变量。在循环初次执行时
forloop.revcounter 将被设置为序列中项的总数。最后一次循环执行中,这个变量将被置1。
forloop.revcounter0 类似于 forloop.revcounter ,但它以0做为结束索引。在第一次执行循环时,该变量会被置为序列的项的个数减1。在最后一次迭代时,该变量为0。
forloop.first 是一个布尔值。在第一次执行循环时该变量为True,在下面的情形中这个变量是很有用的。
{% for object in objects %} {% if forloop.first %}<li class="first">{% else %}<li>{% endif %} {{ object }} </li> {% endfor %}
forloop.last 是一个布尔值;在最后一次执行循环时被置为True。一个常见的用法是在一系列的链接之间放置管道符(|)
{% for link in links %}{{ link }}{% if not forloop.last %} | {% endif %}{% endfor %} The above template code might output something like this:: Link1 | Link2 | Link3 | Link4
forloop.parentloop 是一个指向当前循环的上一级循环的 forloop 对象的引用(在嵌套循环的情况下)。例子在此:
{% for country in countries %} <table> {% for city in country.city_list %} <tr> <td>Country #{{ forloop.parentloop.counter }}</td> <td>City #{{ forloop.counter }}</td> <td>{{ city }}</td> </tr> {% endfor %} </table> {% endfor %}
forloop 变量仅仅能够在循环中使用,在模板解析器碰到 {% endfor %} 标签时, forloop 就不可访问了。
Context和forloop变量
在一个 {% for %} 块中,已存在的变量会被移除,以避免 forloop 变量被覆盖。Django会把这个变量移动到 forloop.parentloop 中。通常我们不用担心这个问题,但是一旦我们在模板中定义了 forloop 这个变量(当然我们反对这样做),在 {% for %} 块中它会在 forloop.parentloop 被重新命名。
三、ifequal/ifnotequal
Django模板系统压根儿就没想过实现一个全功能的编程语言,所以它不允许我们在模板中执行Python的语句(还是那句话,要了解更多请参看理念和限制小节)。但是比较两个变量的值并且显示一些结果实在是个太常见的需求了,所以Django提供了 {% ifequal %} 标签供我们使用。
{% ifequal %} 标签比较两个值,当他们相同时,显示在 {% ifequal %} 和 {% endifequal %} 之中所有的值。
下面的例子比较两个模板变量 user 和 currentuser :
{% ifequal user currentuser %} <h1>Welcome!</h1> {% endifequal %}
参数可以是硬编码的字符串,随便用单引号或者双引号引起来,所以下列代码都是正确的:
{% ifequal section 'sitenews' %} <h1>Site News</h1> {% endifequal %} {% ifequal section "community" %} <h1>Community</h1> {% endifequal %}
和 {% if %} 类似, {% ifequal %} 支持可选的 {% else%} 标签:
{% ifequal section 'sitenews' %} <h1>Site News</h1> {% else %} <h1>No News Here</h1> {% endifequal %}
只有模板变量,字符串,整数和小数可以作为 {% ifequal %} 标签的参数。这些是正确的例子:
{% ifequal variable 1 %} {% ifequal variable 1.23 %} {% ifequal variable 'foo' %} {% ifequal variable "foo" %}
其他的一些类型,例如Python的字典类型、列表类型、布尔类型,不能用在 {% ifequal %} 中。 下面是些错误的例子:
{% ifequal variable True %} {% ifequal variable [1, 2, 3] %} {% ifequal variable {'key': 'value'} %}
如果你需要判断变量是真还是假,请使用 {% if %} 来替代 {% ifequal %} 。
四、注释
象HTML和其他的语言例如python一样,Django模板系统也允许注释。 注释使用 {# #} :
{# This is a comment #}
注释的内容不会在模板渲染时输出。
注释不能跨多行。这个限制是为了提高模板解析的性能。在下面这个模板中,输出结果和模板本身是 完全一样的(也就是说,注释标签并没有被解析为注释):
This is a {# this is not
a comment #}
test.
五、其他总结
(1)block 定义一个子模板可以覆盖的块,在模板中(上一节)有使用示例
(2)comment 注释,{% comment %} 和 {% endcomment %}之间的内容被解释为注释
(3)crsf_token 一个防止CSRF攻击(跨站点请求伪造)的标签
(4)debug 输出所有的调试信息,包括当前上下文和导入的模块
(5)extends 表示说当前模板继承了一个父模板 接受一个包含父模板名字的变量或者字符串常量
(6)load 加载一个自定义的模板标签集合,见单独的一节讲解
(7)url 返回一个绝对路径的引用(没有域名的url),接受的第一个参数是一个视图函数的名字,然后从urls配置文件里面找到那个视图函数对应的url,
(8)autoescape 控制当前自动转义的行为,有on和off两个选项
{% autoescape on %}
{{ body }}
{% endautoescape %}
(9)cycle 循环给出的字符串或者变量,可以混用
{% for o in some_list %} <tr class="{% cycle 'row1' rowvalue2 'row3' %}"> ... </tr> {% endfor %}
值得注意的是,这里的变量的值默认不是自动转义的,要么你相信你的变量,要么你就是用强制转义的方法,
{% for o in some_list %} <tr class="{% filter force_escape %}{% cycle rowvalue1 rowvalue2 %}{% endfilter %}"> ... </tr> {% endfor %}
在某些情况下,你可能想循环外部引用循环的下一个值,这时你需要用as给cycle标签一个名字,这个名字代表的是当前循环的值,但你可以在cycle标签里面是用这个变量来获得循环的下一个值。
<tr> <td class="{% cycle 'row1' 'row2' as rowcolors %}">...</td> <td class="{{ rowcolors }}">...</td> </tr> <tr> <td class="{% cycle rowcolors %}">...</td> <td class="{{ rowcolors }}">...</td> </tr>
渲染的结果是
<tr> <td class="row1">...</td> <td class="row1">...</td> </tr> <tr> <td class="row2">...</td> <td class="row2">...</td> </tr>
但是cycle标签一旦定义,默认就会用循环的第一个值,当你仅仅是想定义一个循环,而不想打印循环的值的时候(比如你在父模板定义变量以方便继承),你可以是用cycle的silent参数(必须保证silent是cycle的最后一个参数,并且silent也具有继承的特点,尽管第二行的cycle没有silent参数,但由于rowcoclors是前面定义的且包含silent参数的,第二个cycle也具有silent 循环的特点。
{% cycle 'row1' 'row2' as rowcolors silent %} {% cycle rowcolors %}
(10)filter 通过可用的过滤器过滤内容,过滤器之间还可以相互(调用)
{% filter force_escape|lower %} This text will be HTML-escaped, and will appear in all lowercase. {% endfilter %}
(11)firstof 返回列表中第一个可用(非False)的变量或者字符串,注意的是firstof中的变量非自动转义
{% firstof var1 var2 var3 "fallback value" %}
(12)for...empty 如果for循环的参数-列表为空,将执行empty里面的内容
<ul> {% for athlete in athlete_list %} <li>{{ athlete.name }}</li> {% empty %} <li>Sorry, no athlete in this list!</li> {% endfor %} <ul>
(13)ifchange
检测一个值在循环的最后有没有改变
所以这个标签实在循环里面是用的,有两个用法:
没有接受参数时,比较的是ifchange标签里面的内容相比以前是否有变化,有变化时生效
接受一个或以上各参数的时候,如果有一个或者以上的参数发生变化时,有变化时生效
ifchange可以有else标签
{% for match in matches %} <div style="background-color: {% ifchanged match.ballot_id %} {% cycle "red" "blue" %} {% else %} grey {% endifchanged %} ">{{ match }}</div> {% endfor %}
(14)ifequal 仅当两个参数相等的时候输出块的内容,可以配合else输出
{% ifequal user.username "adrian" %} ... {% endifequal %}
(15)include
加载一个模板并用当前上下文(include该模板的模板的上下文)渲染它,接受一个变量或者字符串参数
当然你也可以在include的时候传递一些参数进来
{% include "name_snippet.html" with person="Jane" greeting="Hello" %}
如果你只想接受传递的参数,不接受当前模板的上下文时,你可以是用only参数
{% include "name_snippet.html" with greeting="Hi" only %}
(16)now 显示当前的时间日期,接受格式化字符串的参数
It is {% now "jS F Y H:i" %}
参数有已经定义好的一些参考参数: DATE_FORMAT(月日年), DATETIME_FORMAT(月日年时),SHORT_DATE_FORMAT(月/日/年) or SHORT_DATETIME_FORMAT(月/日/年/时)
(17)spaceless 移除html标签之间的空格,注意是标签之间的空格,标签与内容之间的空格不会被删除
{% spaceless %} <p> <a href="foo/">Foo</a> </p> {% endspaceless %}
结果是
<p><a href="foo/">Foo</a></p>
(18)ssi 在页面上输出给定文件的内容
{% ssi /home/html/ljworld.com/includes/right_generic.html %}
使用parsed参数可以使得输入的内容可以作为一个模板从而可以使用当前模板的上下文
{% ssi /home/html/ljworld.com/includes/right_generic.html parsed %}
(19)with 用更简单的变量名缓存复杂的变量名
{% with total=business.employees.count %} {{ total }} employee{{ total|pluralize }} {% endwith %}
尽管初衷是这样,但你不必都是如此,哈哈
{% with alpha=1 beta=2 %} ... {% endwith %}