模板

一个简单的模板示例

<html>
    <head><title>Ordering notice</title></head>
<body>
<h1>Ordering notice</h1>
<p>Dear {{ person_name }},</p>
<p>Thanks for placing an order from {{ company }}. It's scheduled to
ship on {{ ship_date|date:F j, Y }}.</p>
<p>Here are the items you've ordered:</p>

<ul>
{% for item in item_list %}
    <li>{{ item }}</li>
{% endfor %}
</ul>

{% if ordered_warranty %}
    <p>Your warranty information will be included in the packaging.</p>
{% else %}
    <p>You didn't order a warranty, so you're on your own when
    the products inevitably stop working.</p>
{% endif %}

<p>Sincerely,<br />{{ company }}</p>
</body>
</html>


内容解析

  1. 变量:用两个大括号括起来的文字(例如 {{ person_name }} )称为 变量(variable) 。这意味着在此处插入指定变量的值。
  2. 模板标签(template tag):被大括号和百分号包围的文本(例如 {% if ordered_warranty %} )是 模板标签。标签(tag)定义比较明确,即: 仅通知模板系统完成某些工作的标签。
  3. 过滤器:{{ship_date|date:"F j, Y" }},我们将变量ship_date传递给date过滤器,同时指定参数"F j,Y"。date过滤器根据参数进行格式输出。过滤器是用管道符(|)来调用的,具体可以参见Unix管道符。

使用模板系统

在Python代码中使用Django模板的最基本方式如下:

  1. 可以用原始的模板代码字符串创建一个 Template 对象, Django同样支持用指定模板文件路径的方式来创建 Template 对象;
  2. 调用模板对象的render方法,并且传入一套变量context。它将返回一个基于模板的展现字符串,模板中的变量和标签会被context值替换。

示例代码:

from django import template
# 创建 Template 对象
t = template.Template('My name is {{ name }}.')
# 渲染模板
c = template.Context({'name': 'Adrian'})
print t.render(c)


必须指出的一点是,t.render(c)返回的值是一个Unicode对象,不是普通的Python字符串。 你可以通过字符串前的u来区分。 在框架中,Django会一直使用Unicode对象而不是普通的字符串。 如果你明白这样做给你带来了多大便利的话,尽可能地感激Django在幕后有条不紊地为你所做这这么多工作吧。 如果不明白你从中获益了什么,别担心。你只需要知道Django对Unicode的支持,将让你的应用程序轻松地处理各式各样的字符集,而不仅仅是基本的A- Z英文字符。

Django模板系统的基本规则

  1. 写模板,
  2. 创建 Template 对象,
  3. 创建 Context ,
  4. 调用 render() 方法。

Django 模板解析非常快捷。大部分的解析工作都是在后台通过对简短正则表达式一次性调用来完成。 这和基于 XML 的模板引擎形成鲜明对比,那些引擎承担了 XML 解析器的开销,且往往比 Django 模板渲染引擎要慢上几个数量级。

深度变量的查找

在到目前为止的例子中,我们通过 context 传递的简单参数值主要是字符串,还有一个 datetime.date 范例。 然而,模板系统能够非常简洁地处理更加复杂的数据结构,例如list、dictionary和自定义的对象。

在 Django 模板中遍历复杂数据结构的关键是句点字符 (.)。

代码示例:

from django.template import Template, Context

person = {'name': 'Sally', 'age': '43'}
t = Template('{{ person.name }} is {{ person.age }} years old.')
c = Context({'person': person})
t.render(c)


点语法也可以用来引用对象的方法。 例如,每个 Python 字符串都有 upper() 和 isdigit() 方法,你在模板中可以使用同样的句点语法来调用它们:

>>>from django.template import Template, Context
>>>t = Template('{{ var }} -- {{ var.upper }} -- {{ var.isdigit }}')
>>>t.render(Context({'var': 'hello'}))
u'hello -- HELLO -- False'
>>> t.render(Context({'var': '123'}))
u'123 -- 123 -- True'


最后,句点也可用于访问列表索引,例如:

>>> from django.template import Template, Context
>>> t = Template('Item 2 is {{ items.2 }}.')
>>> c = Context({'items': ['apples', 'bananas', 'carrots']})
>>> t.render(c)
u'Item 2 is carrots.'


方法调用行为

方法调用比其他类型的查找略为复杂一点。 以下是一些注意事项:

在方法查找过程中,如果某方法抛出一个异常,除非该异常有一个 silent_variable_failure 属性并且值为 True ,否则的话它将被传播。如果异常被传播,模板里的指定变量会被置为空字符串。

仅在方法无需传入参数时,其调用才有效。 否则,系统将会转移到下一个查找类型(列表索引查找)。

>

显然,有些方法是有副作用的,好的情况下允许模板系统访问它们可能只是干件蠢事,坏的情况下甚至会引发安全漏洞。

>

例如,你的一个 BankAccount 对象有一个 delete() 方法。 如果某个模板中包含了像 {{ account.delete }}这样的标签,其中

account

>

又是BankAccount 的一个实例,请注意在这个模板载入时,account对象将被删除。

>

要防止这样的事情发生,必须设置该方法的 alters_data 函数属性:

例如:

def delete(self):
    # Delete the account
delete.alters_data = True


模板系统不会执行任何以该方式进行标记的方法。 接上面的例子,如果模板文件里包含了 {{ account.delete }} ,对象又具有 delete()方法,而且delete() 有alters_data=True这个属性,那么在模板载入时, delete()方法将不会被执行。 它将静静地错误退出。

如何处理无效变量

默认情况下,如果一个变量不存在,模板系统会把它展示为空字符串,不做任何事情来表示失败。 例如:

>>> from django.template import Template, Context
>>> t = Template('Your name is {{ name }}.')
>>> t.render(Context())
u'Your name is .'


系统静悄悄地表示失败,而不是引发一个异常,因为这通常是人为错误造成的。

这种情况下,因为变量名有错误的状况或名称, 所有的查询都会失败。 现实世界中,对于一个web站点来说,如果仅仅因为一个小的模板语法错误而造成无法访问,这是不可接受的。

玩一玩上下文(context)对象

多数时间,你可以通过传递一个完全填充(full populated)的字典给 Context() 来初始化 上下文(Context) 。 但是初始化以后,你也可以使用标准的Python字典语法(syntax)向

上下文(Context)

对象添加或者删除条目:

>>> from django.template import Context
>>> c = Context({foo: bar})
>>> c['foo']
'bar'

>>> del c['foo']
>>> c['foo']
Traceback (most recent call last):
  ...
KeyError: 'foo'

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