方法调用要比其他的查询稍微复杂一点,下面是需要记住的几点:

1,在方法查询的时候,如果一个方法触发了异常,这个异常会传递从而导致渲染失
败,但是如果异常有一个值为True的silent_variable_failure属性,这个变量会渲染成空string:

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
>>> t = Template("My name is {{ person.first_name }}.")   

>>> class PersonClas3:

... def first_name(self):

... raise AssertionError, "foo"

>>> p = PersonClass3()

>>> t.render(Context({"person": p}))

Traceback (most recent call last):

...

AssertionError: foo

>>> class SilentAssetionError(AssertionError):

... silent_variable_failure = True

>>> class PersonClass4:

... def first_name(self):

... raise SilentAssertionError

>>> p = PersonClass4()

>>> t.render(Context({"person": p}))

"My name is ."

2,方法调用仅仅在它没有参数时起作用,否则系统将继续查找下一个类型(列表索引查询)

3,显然一些方法有副作用,让系统访问它们是很愚蠢的,而且很可能会造成安全性问题。

例如你有一个BankAccount对象,该对象有一个delete()方法,模板系统不应该允许做下面的事情

1
I will now delete this valuable data. {{ account.delete }} 

为了防止这种状况,可以在方法里设置一个方法属性alters_data

如果设置了alters_data=True的话模板系统就不会执行这个方法:

代码

1
2
3
4
5
def delete(self):   

# Delete the account

delete.alters_data = True

不合法的变量怎样处理

默认情况下如果变量不存在,模板系统会把它渲染成空string,例如:

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
>>> from django.template import Template, Context   

>>> t = Template('Your name is {{ name }}.')

>>> t.render(Context())

'Your name is .'

>>> t.render(Context({'var': 'hello'}))

'Your name is .'

>>> t.render(Context({'NAME': 'hello'}))

'Your name is .'

>>> t.render(Context({'Name': 'hello'}))

'Your name is .'

系统会静悄悄地显示错误的页面,而不是产生一个异常,因为这种情况通常是人为的错误。

在现实情形下,一个web站点因为一个模板代码语法的错误而变得不可用是不可接受的。

我们可以通过设置Django配置更改Django的缺省行为,第10章扩展模板引擎会我们会讨论这个

玩玩Context对象

大多数情况下你初始化Context对象会传递一个字典给Context()

一旦你初始化了Context,你可以使用标准Python字典语法增减Context对象的items:

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
>>> from django.template import Context   

>>> c = Context({"foo": "bar"})

>>> c['foo']

'bar'

>>> del c['foo']

>>> c['foo']

''

>>> c['newvariable'] = 'hello'

>>> c['newvariable']

'hello'

Context对象是一个stack,你可以push()和pop()

如果你pop()的太多的话它将触发django.template.ContextPopException:

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
>>> c = Context()   

>>> c['foo'] = 'first level'

>>> c.push()

>>> c['foo'] = 'second level'

>>> c['foo']

'second level'

>>> c.pop()

>>> c['foo']

'first level'

>>> c['foo'] = 'overwritten'

>>> c['foo']

'overwritten'

>>> c.pop()

Traceback (most recent call last):

...

django.template.ContextPopException

if/else

{% if %}标签计算一个变量值,如果是“true”,即它存在、不为空并且不是false的boolean值
系统则会显示{% if %}{% endif %}间的所有内容:

代码

1
2
3
4
5
6
7
8
9
{% if today_is_weekend %}   

<p>Welcome to the weekend!</p>

{% else %}

<p>Get back to work.</p>

{% endif %}

{% if %}标签接受and,or或者not来测试多个变量值或者否定一个给定的变量,例如:

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
{% 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,否则逻辑容易产生歧义,例如下面的标签是不合法的:

代码

1
{% if athlete_list and coach_list or cheerleader_list %}  

如果你想结合and和or来做高级逻辑,只需使用嵌套的{% if %}标签即可:

代码

1
2
3
4
5
6
7
8
9
{% if athlete_list %}   

{% if coach_list or cheerleader_list %}

We have athletes, and either coaches or cheerleaders!

{% endif %}

{% endif %}

多次使用同一个逻辑符号是合法的:

代码

1
{% if athlete_list or coach_list or parent_list or teacher_list %}  

没有{% elif %}标签,使用嵌套的{% if %}标签可以做到同样的事情:

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
{% 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,X是用来遍历Y的变量

每次循环模板系统都会渲染{% for %}{% endfor %}之间的所有内容

例如,显示给定athlete_list变量来显示athlete列表:

代码

1
2
3
4
5
6
7
8
9
<ul>  

{% for athlete in athlete_list %}

<li>{{ athlete.name }}</li>

{% endfor %}

</ul>

在标签里添加reversed来反序循环列表:

代码

1
2
3
4
5
{% for athlete in athlete_list reversed %}   

...

{% endfor %}

{% for %}标签可以嵌套:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
{% for country in countries %}   

<h1>{{ country.name }}</h1>

<ul>

{% for city in country.city_list %}

<li>{{ city }}</li>

{% endfor %}

</ul>

{% endfor %}

系统不支持中断循环,如果你想这样,你可以改变你想遍历的变量来使得变量只包含你想遍历的值

类似的,系统也不支持continue语句

{% for %}标签内置了一个forloop模板变量,这个变量含有一些属性可以提供给你一些关于循环的信息

1,forloop.counter表示循环的次数,它从1开始计数,第一次循环设为1,例如:

代码

1
2
3
4
5
{% for item in todo_list %}   

<p>{{ forloop.counter }}: {{ item }}</p>

{% endfor %}

2,forloop.counter0类似于forloop.counter,但它是从0开始计数,第一次循环设为0
3,forloop.revcounter表示循环中剩下的items数量,第一次循环时设为items总数,最后一次设为1
4,forloop.revcounter0类似于forloop.revcounter,但它是表示的数量少一个,即最后一次循环时设为0
5,forloop.first当第一次循环时值为True,在特别情况下很有用:

代码

1
2
3
4
5
6
7
8
9
{% for object in objects %}   

{% if forloop.first %}<li class="first">{% else %}<li>{% endif %}

{{ object }}

</li>

{% endfor %}

6,forloop.last当最后一次循环时值为True

代码

1
{% for link in links %}{{ link }}{% if not forloop.last %} | {% endif %}{% endfor %}  

7,forloop.parentloop在嵌套循环中表示父循环的forloop:

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
{% 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的变量,Django会用{% for %}标签替代它

Django会在for标签的块中覆盖你定义的forloop变量的值

在其他非循环的地方,你的forloop变量仍然可用

我们建议模板变量不要使用forloop,如果你需要这样做来访问你自定义的forloop,你可以使用forloop.parentloop

ifequal/ifnotequal

Django模板系统并不是一个严格意义上的编程语言,所以它并不允许我们执行Python语句

然而在模板语言里比较两个值并且在他们一致的时候显示一些内容,确实是一个在常见不过的需求了——所以Django提供了ifequal标签。

{% ifequal %}比较两个值,如果相等,则显示{% ifequal %}{% endifequal %}之间的所有内容:

代码

1
2
3
4
5
{% ifequal user currentuser %}   

<h1>Welcome!</h1>

{% endifequal %}

参数可以是硬编码的string,单引号和双引号均可,下面的代码是合法的:

代码

1
2
3
4
5
6
7
8
9
10
11
{% ifequal section 'sitenews' %}   

<h1>Site News</h1>

{% endifequal %}

{% ifequal section "community" %}

<h1>Community</h1>

{% endifequal %}

{% if %}一样,{% ifequal %}标签支持{% else %}

代码

1
2
3
4
5
6
7
8
9
{% ifequal section 'sitenews' %}   

<h1>Site News</h1>

{% else %}

<h1>No News Here</h1>

{% endifequal %}

其它的模板变量,strings,integers和小数都可以作为{% ifequal %}的参数:

代码

1
2
3
4
5
6
7
{% ifequal variable 1 %}   

{% ifequal variable 1.23 %}

{% ifequal variable 'foo' %}

{% ifequal variable "foo" %}

其它的Python类型,如字典、列表或booleans不能硬编码在{% ifequal %}里面,下面是不合法的:

代码

1
2
3
4
5
{% ifequal variable True %}   

{% ifequal variable [1, 2, 3,]%}

{% ifequal variable {'key': 'value'} %}

如果你需要测试某个变量是true或false,用