The Django Book:第4章 Django模板系统
revised by xin_wang
前面的章节我们看到如何在视图中返回HTML,但是HTML是硬编码在Python代码中的
这会导致几个问题:
1,显然,任何页面的改动会牵扯到Python代码的改动
网站的设计改动会比Python代码改动更频繁,所以如果我们将两者分离开会更方便
2,其次,写后台Python代码与设计HTML是不同的工作,更专业的Web开发应该将两者分开
页面设计者和HTML/CSS程序员不应该编辑Python代码,他们应该与HTML打交道
3,程序员写Python代码同时页面设计者写HTML模板会更高效,而不是一个人等待另一个人编辑同样的文件
因此,使用Django的模板系统分离设计和Python代码会更干净更易维护
模板系统基础
Django模板是一个string文本,它用来分离一个文档的展现和数据
模板定义了placeholder和表示多种逻辑的tags来规定文档如何展现
通常模板用来输出HTML,但是Django模板也能生成其它基于文本的形式
让我们来看看一个简单的模板例子:
这个模板本质上是HTML,但是夹杂了一些变量和模板标签:
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模板支持多种内建的块标签,并且你可以写你自己的标签
使用模板系统
在Python代码中使用模板系统,请按照下面的步骤:
1,用模板代码创建一个Template对象
Django也提供指定模板文件路径的方式创建Template对象
2,使用一些给定变量context调用Template对象的render()方法
这将返回一个完全渲染的模板,它是一个string,其中所有的变量和块标签都会根据context得到值
创建模板对象
最简单的方式是直接初始化它,Template类在django.template模块中,初始化方法需要一个参数
下面进入Python交互环境看看:
你将看到如下信息
0xb7d5f24c每次都会改变,但是无所谓,它是Template对象的Python“identity”
在这本书中,我们会在Python的交互式会话环境中展示一些示例。当你看到三个大于号'>>>',就可以确定是在交互环境中了。
如果你从本书中拷贝代码,记得不要拷贝这些大于号。
当你创建Template对象,模板系统会编译模板代码,并准备渲染
如果你的模板代码有语法错误,调用Template()方法会触发TemplateSyntaxError异常
系统触发TemplateSyntaxError异常可能出于以下情况:
1,不合法的块标签
2,合法块标签接受不合法的参数
3,不合法的过滤器
4,合法过滤器接受不合法的参数
5,不合法的模板语法
6,块标签没关
渲染模板
一旦你拥有一个Template对象,你可以通过给一个context来给它传递数据
context是一个变量及赋予的值的集合,模板使用它来得到变量的值,或者对于块标签求值
这个context由django.template模块的Context类表示
它的初始化函数有一个可选的参数:一个映射变量名和变量值的字典
通过context调用Template对象的render()方法来填充模板,例如:
变量名必须以字母(A-Z或a-z)开始,可以包含数字,下划线和小数点,变量名大小写敏感
下面是一个模板编译和渲染的例子,使用这章开始时的模板例子:
让我们来看看都做了些什么:
1,我们import Template和Context类,它们都在django.template模块里面
2,我们把模板文本存储在raw_template变量里,我们使用"""来构建string,它可以跨越多行
3,我们创建模板对象t,并给Template类的初始化函数传递raw_template变量
4,我们从Python的标准库import datetime模块,下面会用到它
5,我们创建一个context对象c,它的初始化函数使用一个映射变量名和变量值的字典
例如我们指定person_name的值为'John Smith',product的值为'Super Lawn Mower'等等
6,最后,我们调用模板对象的render()方法,参数为context对象c
这将返回渲染后的模板,将模板中的变量值替换并计算块标签的结果
如果你刚接触Python,你可能会问为什么输出中包含了新行字符'\n'而不是换行
这是因为Python交互环境中调用t.render(c)会显示string的representation而不是string的值
如果你想看到换行而不是'\n',使用print t.render(c)即可
上面是使用Django模板系统的基础,只是创建一个模板对象和context对象然后调用render()方法
同一个模板,多个context的情况:
一旦你创建了一个模板对象,你可以渲染多个context,例如:
无论何时,你使用同一个模板来渲染多个context的话,创建一次Template对象然后调用render()多次会更高效
Django的模板解析非常快,在后台,大部分的解析通过一个单独的对正则表达式的调用来做
这与基于XML的模板引擎形成鲜明对比,XML解析器比Django的模板渲染系统慢很多
Context变量查找
上面的例子中,我们给模板context传递了简单的值,大部分是string,以及一个datetime.date
尽管如此,模板系统优雅的处理更复杂的数据结构,如列表,字典和自定义对象
在Django模板系统中处理复杂数据结构的关键是使用(.)字符
使用小数点来得到字典的key,属性,对象的索引和方法
下面通过例子来解释,通过(.)访问字典的key:
通过(.)来访问对象的属性:
下面的例子使用一个自定义类:
小数点也可以用来调用列表的索引:
负数的列表索引是不允许的,例如模板变量{{ items.-1 }}将触发TemplateSyntaxError
最后小数点还可以用来访问对象的方法,例如Python的string有upper()和isdigit()方法:
注意,调用方法时你不能加括号,你也不能给方法传递参数
你只能调用没有参数的方法,后面我们会解释这些
总结一下,当模板系统遇到变量名里有小数点时会按以下顺序查找:
1,字典查找,如foo["bar"]
2,属性查找,如foo.bar
3,方法调用,如foo.bar()
3,列表的索引查找,如foo[bar]
小数点可以多级纵深查询,例如{{ person.name.upper }}表示字典查询person['name']然后调用upper()方法
关于方法调用
方法调用要比其他的查询稍微复杂一点,下面是需要记住的几点:
1,在方法查询的时候,如果一个方法触发了异常,这个异常会传递从而导致渲染失
败,但是如果异常有一个值为True的silent_variable_failure属性,这个变量会渲染成空string:
2,方法调用仅仅在它没有参数时起作用,否则系统将继续查找下一个类型(列表索引查询)
3,显然一些方法有副作用,让系统访问它们是很愚蠢的,而且很可能会造成安全性问
题。
例如你有一个BankAccount对象,该对象有一个delete()方法,模板系统不应该允许做下面的事情
I will now delete this valuable data. {{ account.delete }}
为了防止这种状况,可以在方法里设置一个方法属性alters_data
如果设置了alters_data=True的话模板系统就不会执行这个方法:
不合法的变量怎样处理
默认情况下如果变量不存在,模板系统会把它渲染成空string,例如:
系统会静悄悄地显示错误的页面,而不是产生一个异常,因为这种情况通常是人为的错误。
在现实情形下,一个web站点因为一个模板代码语法的错误而变得不可用是不可接受的。
我们可以通过设置Django配置更改Django的缺省行为,第10章扩展模板引擎会我们会讨论这个
玩玩Context对象
大多数情况下你初始化Context对象会传递一个字典给Context()
一旦你初始化了Context,你可以使用标准Python字典语法增减Context对象的items:
Context对象是一个stack,你可以push()和pop()
如果你pop()的太多的话它将触发django.template.ContextPopException:
第10章你会看到使用Context作为stack自定义模板标签
模板标签和过滤器基础
我们已经提到模板系统使用内建的标签和过滤器
这里我们看看常见的,附录6包含了完整的内建标签和过滤器,你自己熟悉那个列表来了解可以做什么是个好主意
if/else
{% if %}标签计算一个变量值,如果是“true”,即它存在、不为空并且不是false的boolean值
系统则会显示{% if %}和{% endif %}间的所有内容:
{% if %}标签接受and,or或者not来测试多个变量值或者否定一个给定的变量,例如:
{% if %}标签不允许同一标签里同时出现and和or,否则逻辑容易产生歧义,例如下面的标签是不合法的:
如果你想结合and和or来做高级逻辑,只需使用嵌套的{% if %}标签即可:
多次使用同一个逻辑符号是合法的:
没有{% elif %}标签,使用嵌套的{% if %}标签可以做到同样的事情:
确认使用{% endif %}来关闭{% if %}标签,否则Django触发TemplateSyntaxError
for
{% for %}标签允许你按顺序遍历一个序列中的各个元素
Python的for语句语法为for X in Y,X是用来遍历Y的变量
每次循环模板系统都会渲染{% for %}和{% endfor %}之间的所有内容
例如,显示给定athlete_list变量来显示athlete列表:
在标签里添加reversed来反序循环列表:
系统不支持中断循环,如果你想这样,你可以改变你想遍历的变量来使得变量只包含你想遍历的值
类似的,系统也不支持continue语句,本章后面的“哲学和限制”会解释设计的原则
{% for %}标签内置了一个forloop模板变量,这个变量含有一些属性可以提供给你一些关于循环的信息
1,forloop.counter表示循环的次数,它从1开始计数,第一次循环设为1,例如:
2,forloop.counter0类似于forloop.counter,但它是从0开始计数,第一次循环设为0
3,forloop.revcounter表示循环中剩下的items数量,第一次循环时设为items总数,最后一次设为1
4,forloop.revcounter0类似于forloop.revcounter,但它是表示的数量少一个,即最后一次循环时设为0
5,forloop.first当第一次循环时值为True,在特别情况下很有用:
6,forloop.last当最后一次循环时值为True
revised by xin_wang
前面的章节我们看到如何在视图中返回HTML,但是HTML是硬编码在Python代码中的
这会导致几个问题:
1,显然,任何页面的改动会牵扯到Python代码的改动
网站的设计改动会比Python代码改动更频繁,所以如果我们将两者分离开会更方便
2,其次,写后台Python代码与设计HTML是不同的工作,更专业的Web开发应该将两者分开
页面设计者和HTML/CSS程序员不应该编辑Python代码,他们应该与HTML打交道
3,程序员写Python代码同时页面设计者写HTML模板会更高效,而不是一个人等待另一个人编辑同样的文件
因此,使用Django的模板系统分离设计和Python代码会更干净更易维护
模板系统基础
Django模板是一个string文本,它用来分离一个文档的展现和数据
模板定义了placeholder和表示多种逻辑的tags来规定文档如何展现
通常模板用来输出HTML,但是Django模板也能生成其它基于文本的形式
让我们来看看一个简单的模板例子:
- <html>
- <head><title>Ordering notice</title></head>
- <body>
- <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>
- {% endif %}
- <p>Sincerely,<br />{{ company }}</p>
- </body>
- </html>
<html> <head><title>Ordering notice</title></head> <body> <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> {% endif %} <p>Sincerely,<br />{{ company }}</p> </body> </html>
这个模板本质上是HTML,但是夹杂了一些变量和模板标签:
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模板支持多种内建的块标签,并且你可以写你自己的标签
使用模板系统
在Python代码中使用模板系统,请按照下面的步骤:
1,用模板代码创建一个Template对象
Django也提供指定模板文件路径的方式创建Template对象
2,使用一些给定变量context调用Template对象的render()方法
这将返回一个完全渲染的模板,它是一个string,其中所有的变量和块标签都会根据context得到值
创建模板对象
最简单的方式是直接初始化它,Template类在django.template模块中,初始化方法需要一个参数
下面进入Python交互环境看看:
- >>> from django.template import Template
- >>> t = Template("My name is {{my_name}}.")
- >>> print t
>>> from django.template import Template >>> t = Template("My name is {{my_name}}.") >>> print t
你将看到如下信息
<django.template.Template object at 0xb7d5f24c>
0xb7d5f24c每次都会改变,但是无所谓,它是Template对象的Python“identity”
在这本书中,我们会在Python的交互式会话环境中展示一些示例。当你看到三个大于号'>>>',就可以确定是在交互环境中了。
如果你从本书中拷贝代码,记得不要拷贝这些大于号。
当你创建Template对象,模板系统会编译模板代码,并准备渲染
如果你的模板代码有语法错误,调用Template()方法会触发TemplateSyntaxError异常
- >>> from django.template import Template
- >>> t = Template('{%notatag%}')
- Traceback (most recent call last):
- File "<stdin>", line 1, in ?
- ...
- django.template.TemplateSyntaxError: Invalid block tag: 'notatag'
>>> from django.template import Template >>> t = Template('{%notatag%}') Traceback (most recent call last): File "<stdin>", line 1, in ? ... django.template.TemplateSyntaxError: Invalid block tag: 'notatag'
系统触发TemplateSyntaxError异常可能出于以下情况:
1,不合法的块标签
2,合法块标签接受不合法的参数
3,不合法的过滤器
4,合法过滤器接受不合法的参数
5,不合法的模板语法
6,块标签没关
渲染模板
一旦你拥有一个Template对象,你可以通过给一个context来给它传递数据
context是一个变量及赋予的值的集合,模板使用它来得到变量的值,或者对于块标签求值
这个context由django.template模块的Context类表示
它的初始化函数有一个可选的参数:一个映射变量名和变量值的字典
通过context调用Template对象的render()方法来填充模板,例如:
- >>> from django.template import Context, Template
- >>> t = Template("My name is {{name}}.")
- >>> c = Context({"name": "Stephane"})
- >>> t.render(c)
- 'My name is Stephane.'
>>> from django.template import Context, Template >>> t = Template("My name is {{name}}.") >>> c = Context({"name": "Stephane"}) >>> t.render(c) 'My name is Stephane.'
变量名必须以字母(A-Z或a-z)开始,可以包含数字,下划线和小数点,变量名大小写敏感
下面是一个模板编译和渲染的例子,使用这章开始时的模板例子:
- >>> from django.template import Template, Context
- >>> raw_template = """<p>Dear {{ person_name }},</p>
- ...
- ... <p>Thanks for ordering {{ product }} from {{ company }}. It's scheduled to
- ... ship on {{ ship_date|date:"F j, Y" }}.</p>
- ...
- ... {% if ordered_warranty %}
- ... <p>Your warranty information will be included in the packaging.</p>
- ... {% endif %}
- ...
- ... <p>Sincerely,<br />{{ company }}</p>"""
- >>> t = Template(raw_template)
- >>> import datetime
- >>> c = Context({'person_name': 'John Smith',
- ... 'product': 'Super Lawn Mower',
- ... 'company': 'Outdoor Equipment',
- ... 'ship_date': datetime.date(2009, 4, 2),
- ... 'ordered_warranty': True})
- >>> t.render(c)
- "<p>Dear John Smith,</p>\n\n<p>Thanks for ordering Super Lawn Mower from Outdoor Equipment.
- It's scheduled to ship on April 2, 2009.</p>\n\n<p>Your warranty information will be included
- in the packaging.</p>\n\n\n<p>Sincerely,<br />Outdoor Equipment</p>"
>>> from django.template import Template, Context >>> raw_template = """<p>Dear {{ person_name }},</p> ... ... <p>Thanks for ordering {{ product }} from {{ company }}. It's scheduled to ... ship on {{ ship_date|date:"F j, Y" }}.</p> ... ... {% if ordered_warranty %} ... <p>Your warranty information will be included in the packaging.</p> ... {% endif %} ... ... <p>Sincerely,<br />{{ company }}</p>""" >>> t = Template(raw_template) >>> import datetime >>> c = Context({'person_name': 'John Smith', ... 'product': 'Super Lawn Mower', ... 'company': 'Outdoor Equipment', ... 'ship_date': datetime.date(2009, 4, 2), ... 'ordered_warranty': True}) >>> t.render(c) "<p>Dear John Smith,</p>\n\n<p>Thanks for ordering Super Lawn Mower from Outdoor Equipment. It's scheduled to ship on April 2, 2009.</p>\n\n<p>Your warranty information will be included in the packaging.</p>\n\n\n<p>Sincerely,<br />Outdoor Equipment</p>"
让我们来看看都做了些什么:
1,我们import Template和Context类,它们都在django.template模块里面
2,我们把模板文本存储在raw_template变量里,我们使用"""来构建string,它可以跨越多行
3,我们创建模板对象t,并给Template类的初始化函数传递raw_template变量
4,我们从Python的标准库import datetime模块,下面会用到它
5,我们创建一个context对象c,它的初始化函数使用一个映射变量名和变量值的字典
例如我们指定person_name的值为'John Smith',product的值为'Super Lawn Mower'等等
6,最后,我们调用模板对象的render()方法,参数为context对象c
这将返回渲染后的模板,将模板中的变量值替换并计算块标签的结果
如果你刚接触Python,你可能会问为什么输出中包含了新行字符'\n'而不是换行
这是因为Python交互环境中调用t.render(c)会显示string的representation而不是string的值
如果你想看到换行而不是'\n',使用print t.render(c)即可
上面是使用Django模板系统的基础,只是创建一个模板对象和context对象然后调用render()方法
同一个模板,多个context的情况:
一旦你创建了一个模板对象,你可以渲染多个context,例如:
- >>> from django.template import Template, Context
- >>> t = Template('Hello, {{ name }}')
- >>> print t.render(Context({'name': 'John'}))
- Hello, John
- >>> print t.render(Context({'name': 'Julie'}))
- Hello, Julie
- >>> print t.render(Context({'name': 'Pat'}))
- Hello, Pat
>>> from django.template import Template, Context >>> t = Template('Hello, {{ name }}') >>> print t.render(Context({'name': 'John'})) Hello, John >>> print t.render(Context({'name': 'Julie'})) Hello, Julie >>> print t.render(Context({'name': 'Pat'})) Hello, Pat
无论何时,你使用同一个模板来渲染多个context的话,创建一次Template对象然后调用render()多次会更高效
- # Bad
- for name in ('John', 'Julie', 'Pat'):
- t = Template('Hello, {{ name }}')
- print t.render(Context({'name': name}))
- # Good
- t = Template('Hello, {{ name }}')
- for name in ('John', 'Julie', 'Pat'):
- print t.render(Context({'name': name}))
# Bad for name in ('John', 'Julie', 'Pat'): t = Template('Hello, {{ name }}') print t.render(Context({'name': name})) # Good t = Template('Hello, {{ name }}') for name in ('John', 'Julie', 'Pat'): print t.render(Context({'name': name}))
Django的模板解析非常快,在后台,大部分的解析通过一个单独的对正则表达式的调用来做
这与基于XML的模板引擎形成鲜明对比,XML解析器比Django的模板渲染系统慢很多
Context变量查找
上面的例子中,我们给模板context传递了简单的值,大部分是string,以及一个datetime.date
尽管如此,模板系统优雅的处理更复杂的数据结构,如列表,字典和自定义对象
在Django模板系统中处理复杂数据结构的关键是使用(.)字符
使用小数点来得到字典的key,属性,对象的索引和方法
下面通过例子来解释,通过(.)访问字典的key:
- >>> 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)
- 'Sally is 43 years old.'
>>> 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) 'Sally is 43 years old.'
通过(.)来访问对象的属性:
- >>> from django.template import Template, Context
- >>> import datetime
- >>> d = datetime.date(1993, 5, 2)
- >>> d.year
- 1993
- >>> d.month
- 5
- >>> d.day
- 2
- >>> t = Template('The month is {{ date.month }} and the year is {{ date.year }}.')
- >>> c = Context({'date': d})
- >>> t.render(c)
- 'The month is 5 and the year is 1993.'
>>> from django.template import Template, Context >>> import datetime >>> d = datetime.date(1993, 5, 2) >>> d.year 1993 >>> d.month 5 >>> d.day 2 >>> t = Template('The month is {{ date.month }} and the year is {{ date.year }}.') >>> c = Context({'date': d}) >>> t.render(c) 'The month is 5 and the year is 1993.'
下面的例子使用一个自定义类:
- >>> from django.template import Template, Context
- >>> class Person(object):
- ... def __init__(self, first_name, last_name):
- ... self.first_name, self.last_name = first_name, last_name
- >>> t = Template('Hello, {{ person.first_name }} {{ person.last_name }}.')
- >>> c = Context({'person': Person('John', 'Smith')})
- >>> t.render(c)
- 'Hello, John Smith.'
>>> from django.template import Template, Context >>> class Person(object): ... def __init__(self, first_name, last_name): ... self.first_name, self.last_name = first_name, last_name >>> t = Template('Hello, {{ person.first_name }} {{ person.last_name }}.') >>> c = Context({'person': Person('John', 'Smith')}) >>> t.render(c) 'Hello, John Smith.'
小数点也可以用来调用列表的索引:
- >>> from django.template import Template, Context
- >>> t = Template('Item 2 is {{ items.2 }}.')
- >>> c = Contexst({'items': ['apples', 'bananas', 'carrots']})
- >>> t.render(c)
- 'Item 2 is carrots.'
>>> from django.template import Template, Context >>> t = Template('Item 2 is {{ items.2 }}.') >>> c = Contexst({'items': ['apples', 'bananas', 'carrots']}) >>> t.render(c) 'Item 2 is carrots.'
负数的列表索引是不允许的,例如模板变量{{ items.-1 }}将触发TemplateSyntaxError
最后小数点还可以用来访问对象的方法,例如Python的string有upper()和isdigit()方法:
- >>> from django.template import Template, Context
- >>> t = Template('{{ var }} -- {{var.upper }} -- {{ var.isdigit }}')
- >>> t.render(Context({'var': 'hello'}))
- 'hello -- HELLO -- False'
- >>> t.render(Context({'var': '123'}))
- '123 - 123 - True'
>>> from django.template import Template, Context >>> t = Template('{{ var }} -- {{var.upper }} -- {{ var.isdigit }}') >>> t.render(Context({'var': 'hello'})) 'hello -- HELLO -- False' >>> t.render(Context({'var': '123'})) '123 - 123 - True'
注意,调用方法时你不能加括号,你也不能给方法传递参数
你只能调用没有参数的方法,后面我们会解释这些
总结一下,当模板系统遇到变量名里有小数点时会按以下顺序查找:
1,字典查找,如foo["bar"]
2,属性查找,如foo.bar
3,方法调用,如foo.bar()
3,列表的索引查找,如foo[bar]
小数点可以多级纵深查询,例如{{ person.name.upper }}表示字典查询person['name']然后调用upper()方法
- >>> from django.template import Template, Context
- >>> person = {'name': 'Sally', 'age': '43'}
- >>> t = Template('{{ person.name.upper }} is {{ person.age }} years old.')
- >>> c = Context({'person': person})
- >>> t.render(c)
- 'SALLY is 43 years old.'
>>> from django.template import Template, Context >>> person = {'name': 'Sally', 'age': '43'} >>> t = Template('{{ person.name.upper }} is {{ person.age }} years old.') >>> c = Context({'person': person}) >>> t.render(c) 'SALLY is 43 years old.'
关于方法调用
方法调用要比其他的查询稍微复杂一点,下面是需要记住的几点:
1,在方法查询的时候,如果一个方法触发了异常,这个异常会传递从而导致渲染失
败,但是如果异常有一个值为True的silent_variable_failure属性,这个变量会渲染成空string:
- >>> 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 ."
>>> 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()方法,模板系统不应该允许做下面的事情
I will now delete this valuable data. {{ account.delete }}
为了防止这种状况,可以在方法里设置一个方法属性alters_data
如果设置了alters_data=True的话模板系统就不会执行这个方法:
def delete(self): # Delete the account delete.alters_data = True
不合法的变量怎样处理
默认情况下如果变量不存在,模板系统会把它渲染成空string,例如:
- >>> 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 .'
>>> 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:
- >>> from django.template import Context
- >>> c = Context({"foo": "bar"})
- >>> c['foo']
- 'bar'
- >>> del c['foo']
- >>> c['foo']
- ''
- >>> c['newvariable'] = 'hello'
- >>> c['newvariable']
- 'hello'
>>> 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:
- >>> 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
>>> 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
第10章你会看到使用Context作为stack自定义模板标签
模板标签和过滤器基础
我们已经提到模板系统使用内建的标签和过滤器
这里我们看看常见的,附录6包含了完整的内建标签和过滤器,你自己熟悉那个列表来了解可以做什么是个好主意
if/else
{% if %}标签计算一个变量值,如果是“true”,即它存在、不为空并且不是false的boolean值
系统则会显示{% if %}和{% endif %}间的所有内容:
- {% if today_is_weekend %}
- <p>Welcome to the weekend!</p>
- {% else %}
- <p>Get back to work.</p>
- {% endif %}
{% if today_is_weekend %} <p>Welcome to the weekend!</p> {% else %} <p>Get back to work.</p> {% 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 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 %} {% 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 %}
{% 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列表:
<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 %}
{% 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 %}
系统不支持中断循环,如果你想这样,你可以改变你想遍历的变量来使得变量只包含你想遍历的值
类似的,系统也不支持continue语句,本章后面的“哲学和限制”会解释设计的原则
{% for %}标签内置了一个forloop模板变量,这个变量含有一些属性可以提供给你一些关于循环的信息
1,forloop.counter表示循环的次数,它从1开始计数,第一次循环设为1,例如:
{% 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,在特别情况下很有用:
- {% for object in objects %}
- {% if forloop.first %}<li class="first">{% else %}<li>{% endif %}
- {{ object }}
- </li>
- {% endfor %}
{% for object in objects %} {% if forloop.first %}<li class="first">{% else %}<li>{% endif %} {{ object }} </li> {% endfor %}
6,forloop.last当最后一次循环时值为True
{% for link in links %}{{ link }}{% if not f发表评论
相关推荐
- **第4章:Django模板系统** - 深入探讨了Django的模板语言,以及如何创建和管理模板。 - **第5章:数据库交互:模型** - 解释了ORM工作方式,以及如何定义和操作数据模型。 - **第6章:Django管理站点** - 描述了...
创建Django模板的第一步是设置项目的模板目录。通常,我们会在项目的`templates`目录下创建一个或多个子目录,每个子目录对应一个应用。例如,如果项目名为`zqxt`,那么模板目录结构可能如下: ``` project/ zqxt/...
3. 模板(Template):Django模板系统允许开发者用HTML和特定的模板语言来设计用户界面,可以插入变量和控制结构,动态生成网页内容。例如,用户登录页面、任务列表、审批流程界面等。 4. 视图(View):视图是处理...
#### 第四章:Django模板系统 - **模板系统基本知识**:Django模板系统是一种用于生成HTML页面的强大工具,支持变量替换、条件语句、循环等功能。 - **如何使用模板系统**: - **创建模板对象**:使用模板引擎加载...
前端可以使用HTML、CSS和JavaScript,结合Django模板语言来实现动态内容。 3. **多模块设计**: 大型项目通常需要多个模块协同工作。在Django中,每个模块(app)可以独立开发,拥有自己的模型、视图、模板和URL...
3. **模板(Template)**:模板是负责呈现数据的HTML文件,其中可以插入Django模板语言(Django Template Language, DTL)标签,用来动态地渲染数据。例如,在商品详情页,我们可以使用DTL从模型获取商品信息,并将...
本教程是针对Python开发者学习Django框架的优质资源。对于众多渴望掌握Django Web开发的学习者来说...4. 第四章:模板基础 5. 第五章:模型构建 6. 第六章:Django Admin 7. 第七章:表单处理 8. 第八章:高级视图与UR
### 第四章:模型与数据库 Django的ORM允许开发者使用Python类来定义数据库模型。本章将讲解如何创建模型、数据迁移以及如何进行数据库查询。 ### 第五章:视图与URL路由 视图是处理请求并返回响应的部分,而URL...
1. **快速开发**:Django提供了许多内置功能,如认证系统、URL路由、表单处理、模板引擎等,这使得开发者能够快速构建原型或完整的Web应用程序。 2. **模型-模板-视图(MTV)**:Django将业务逻辑、数据模型和用户...
- 模板:定义网页结构,包含动态内容的标签和变量。 3. Django的ORM(对象关系映射)系统: Django的ORM系统提供了强大的数据库操作能力,它允许开发者使用Python编程语言直接操作数据库中的数据,而无需编写SQL...
#### 第四章:模板 - **模板语言**:详细介绍Django模板语言的特点,包括变量的使用、标签的定义等。 - **模板继承**:讲解如何使用模板继承来重用模板代码,减少重复工作。 - **上下文处理器**:介绍上下文...
- **第三方应用**: Django 生态系统中有大量的第三方应用,如 Django Rest Framework 用于构建 RESTful API,Django-CMS 用于内容管理系统等。 **结论** Django 1.0 文档是理解 Django 基础和进阶特性的关键资源。...
本章讲述了Django模板语言的基础知识,包括变量、标签、过滤器,以及如何在模板中编写控制语句和循环。 第7章:处理HTTP。在这一章中,讲解了Django如何处理HTTP请求和响应。包括中间件的概念,以及如何使用中间件...
### 第四章:模板 模板是 Django 中非常重要的组成部分,用于生成动态 HTML 页面。本章深入探讨了 Django 模板语言的语法结构、变量和标签的使用方法,以及如何创建可重用的模板片段。 ### 第五章:模型 模型是 ...
Django拥有丰富的第三方库,如Django REST framework用于构建RESTful API,Django Channels支持WebSocket通信,以及用于权限管理的Django Guardian等。 以上只是Django框架的基本介绍,实际上,Django的功能远不止...
**2.6 编写第一个 Django 应用(第四部分)** - **模板设计**: 设计并渲染模板。 - **数据展示**: 展示数据库中的数据。 **2.7 编写第一个 Django 应用(第五部分)** - **表单创建**: 创建表单类。 - **表单验证...
【Django的资产管理系统源码】是一套使用Python的Django框架编写的简易资产管理软件教程。这个系统虽然规模不大,但包含了实现一个完整管理系统的必要组件,是学习Django开发的良好实践案例。该项目构建在Django 2.2...
3. **模板(Template)**:Django的模板系统用于生成动态HTML。学习如何创建模板文件,使用模板语言进行条件判断、循环、变量渲染和继承,以及如何使用模板过滤器和标签。 4. **视图(View)**:视图是处理用户请求...