Django学习总结之四-模板

在上一章,我们页面显示的html代码是直接编写在python代码中,因为对页面的设计修改工作要比python频繁的多,所以最好将页面设计工作和python代码分离,所以我们引用模板来实现这个功能。

一、模板实例

下面是一个模板的实例:

<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)用大括号括起来的称作:变量,需要对它进行赋值

(2)用大括号和百分号括起来的是:模板标签,即通知模板系统完成某些工作的标签。上文中有两个模板标签:for和if分别实现循环和判断。

(3)第二段有个filter过滤器的使用:

{{ ship_date|date:"F j, Y" }

它是将变量ship_date传递给过滤器date,同时指定参数,过滤器按照参数输出。
二、使用模板

1、基本流程:

(1)用原始的模板代码创建一个Template对象

(2)创建一个Context对象,完成对模板对象中的变量赋值

(3)调用模板对象的render方法,将(2)步生成的context对象作为参数,填充模板,同时返回基于模板的展现字符串,这时其中的变量已经被替换。

实例:

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

转到mysite所在的目录,输入

python manage.py shell

为什么我们运行pythonmanage.pyshell而不是python的。这两个命令都会启动交互解释器,但是manage.pyshell命令有一个重要的不同: 在启动解释器之前,它告诉Django使用哪个设置文件。 Django框架的大部分子系统,包括模板系统,都依赖于配置文件;如果Django不知道使用哪个配置文件,这些系统将不能工作。

>>> from django import template
>>> t = template.Template('My name is {{ name }}.')
>>> print t
<django.template.base.Template object at 0x0220EBD0>
每次创建一个template对象,打印出来的地址都不同。

3、模板渲染

即,对模板内的变量、标签赋值。

使用context来传递数据,一个context是一系列变量和他们的值的集合,然后用template的render方法传递context填充模板。

>>> from django import template
>>> t = template.Template('My name is {{ name }}.')
>>> c = template.Context('name': 'Jim')
>>> t.render(c)
u'My name is Jim.'

实例:

>>> from django.template import Template, Context
>>> raw_template = """<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>
...
... {% 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>"""
>>> t = Template(raw_template)
>>> import datetime
>>> c = Context({'person_name': 'John Smith',
...     'company': 'Outdoor Equipment',
...     'ship_date': datetime.date(2009, 4, 2),
...     'ordered_warranty': False})
>>> t.render(c)
u"<p>Dear John Smith,</p>\n\n<p>Thanks for placing an order from Outdoor
Equipment. It's scheduled to\nship on April 2, 2009.</p>\n\n\n<p>You
didn't order a warranty, so you're on your own when\nthe products
inevitably stop working.</p>\n\n\n<p>Sincerely,<br />Outdoor Equipment
</p>"

输出的结果没有按照\n显示换行,这和python解释器有关,它会按照真实内容显示,如果想显示出换行,使用print t.render(c)

4、一个模板多个渲染

一旦定义了一个模板,就可以渲染多个context

>>> from django.template import  Template, Context
>>> t = Template('My name is {{ name }}.')
>>> print t.render(Context{'name': 'Jim'})
My name is Jim.
>>> print t.render(Context{'name': 'Pat'})
My name is Pat.


>>> from django.template import  Template, Context
>>> t = Template('Hello, {{ name }}')
>>> for name in ('John', 'Juile', 'pat'):
...     print t.render(Context({'name': name}))
...
Hello, John
Hello, Juile
Hello, pat

5、深度查找

通过使用点号(.)遍历模板中复杂的数据结构。

5.1访问字典值

>>> 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)
u'Sally is 43 years old.'
5.2访问对象属性

>>> 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)
u'The month is 5 and the year is 1993.'
5.3访问自定义类的属性

>>> 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)
u'Hello, John Smith.'
5.4引用对象的方法

>>> 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'
每个python字符串都有upper(),lower()和isdigit()方法,分别将字符串转换为大写、小写以及判断是否为数字。这里调用的方法后没有括号,所以只能调用没有参数的方法。

5.5访问列表索引

>>> 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.'
注:不允许使用负数的列表索引

6、句点的查找规则

当模板系统在变量名中遇到句点时,按照以下顺序查找:

  • 字典类型查找:如foo["bar"]
  • 属性查找:如foo.bar
  • 方法调用:foo.bar()
  • 列表类型索引查找:如foo[bar]
句点可以多层深入嵌套查找。
三、模板标签
1、if/else
{% if today_is_weekend %}
    <p>Welcome to the weekend!</p>
{% else %}
    <p>Get back to work.</p>
{% endif %}
if标签检查变量tody_is_weekend ,如果该变量为真,则执行{% if %}和{% endif %}或者和{% else %}之间的内容。{%  else %}是可选的。在python和django模板系统中,以下对象相当于布尔值False:
  • 空列表([ ])
  • 空元组(( ))
  • 空字典({ })
  • 空字符串(' ')
  • 零值(0)
  • 特殊兑现None
  • 对象False
{% if %} 接受and or 或者not 对多个变量做判断,但是不允许在用一个标签中同时使用and 和 or。如以下这种写法不合法:
{% if athlete_list and coach_list or cheerleader_list %}
同时系统不支持用圆括号来组合比较操作,可以使用嵌套的{% 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 %}必须用{% endif %}标签结束。
2、for
循环,语法是for X in Y,每一次循环,模板系统会渲染在{% for %}和{% endfor %}之间的内容。
<ul>
{% for  athlete in athlete_list%}
       <li>{{ athlete.name }}</li>
{% endfor %}
</ul>
还可以嵌套使用for循环。
1、在for循环之前一般先检测列表的大小,当列表为空时,给出必要的提示:
{% if athlete_list %}
	{% for athlete in athlete_list %}
		<p>{{ athlete.name }}</p>
	<% endfor %>
{% else %}
	<p> There are no athletes.</p>
<% endif %>
但是可以使用{%  empty %}标签定义列表为空时的输出内容:
{% for athlete in athlete_list %}
	<p>{{ athlete.name }}</p>
{% empty %}
	<p> There are no athletes.</p>
<% endfor %>
这个和上面的例子等价。
注:django不支持退出循环,也不支持continue,可以通过改变正在迭代的变量退出循环。
2、每个{% for %} 循环里有一个称为forloop的模板变量。
1)forloop.counter:当前循环执行的次数,默认值为1;
2)forloop.counter0:类似forloop.counter 默认值为0;
3)forloop.revcounter:循环中的剩余项。最后一次循环执行时,变量被置为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 %}
6)forloop.last:布尔值,在最后一次执行时被置为true
常见的用途是为列表的每个单词添加逗号:
{% for p in places %}{{ p }}{% if not forloop.last %}, {% endif %}{% endfor %}
7)forloop.parentloop:是一个指向当前循环的上一级循环的 forloop 对象的引用(在嵌套循环的情况下)。 

注:forloop变量仅在循环中使用。
3、ifequal和ifnotequal
{% ifequal %} 标签比较两个值,当他们相等时,显示在 {% ifequal %} 和 {% endifequal %} 之中所有的值。
{% ifequal variable 1 %}
{% ifequal variable 1.23 %}
{% ifequal variable 'foo' %}
{% ifequal variable "foo" %}
{% ifequal section 'sitenews' %}
    <h1>Site News</h1>
{% else %}
    <h1>No News Here</h1>
{% endifequal %}
注:布尔、字典、列表类型不能用在{% ifequal %}中。
4、注释
1)单行注释:{# #}
2)多行注释:可以使用三个引号''' 注释内容 '''
四、过滤器
过滤器是在变量被显示前,修改它的值。
1、{{ name| lower}} 转换文本为小写
2、过滤管道可以被套接,既是说,一个过滤器管道的输出又可以作为下一个管道的输入,如此下去。
{{ my_list|first|upper }}
查找列表的第一个元素,并转换为大写。
3、带有参数的过滤器:过滤器的参数跟随冒号之后并且总是以双引号包含。
{{ bio|truncatewords:"30"}} 显示变量bio的前30个单词。
4、addslashes : 添加反斜杠到任何反斜杠、单引号或者双引号前面。
5、date : 按指定的格式字符串参数格式化 date 或者 datetime 对象:
{pub_date|date:"F j, Y"}
6、length:返回变量的长度。 对于列表,这个参数将返回列表元素的个数。 对于字符串,这个参数将返回字符串中字符的个数。
五、视图中使用模板
1、
方法:单独建立模板文件, 让视图加载该模板文件。
1)、首先将模板的保存位置告诉框架。打开setting.py 配置文件,找到:TEMPLATE_DIRS,添加模板位置路径。最省事的方法是使用绝对路径,在Django项目中建立模板文件夹templates。
import os.path

TEMPLATE_DIRS = (
    os.path.join(os.path.dirname(___file___), 'templates').replace('\\','/'),
)
os.path.dirname(__file__)会获取setting.py 所在的目录,然后这个目录与templates连接。我们可以使用render_to_response()方法进一步简化代码。注:file两侧是两个下划线。
2)、编写模板文件
current_date.html
<html>
<body>
It is now {{current_date}}.
</body>
</html>
3)、编写views.py 文件
from django.shortcuts import render_to_response
import datetime

def current_datetime(request):
	now = datetime.datetime.now()
	return render_to_response('current_date.html',{'current_date': now})
4)、修改urls.py 
from django.conf.urls.defaults import patterns, include, url
from mysite.views import current_datetime

urlpatterns = patterns('',
	('^current_time/$', current_datetime),
)
2、使用locals()
未使用前:
def current_datetime(request):
    now = datetime.datetime.now()
    return render_to_response('current_datetime.html', {'current_date': now})
使用后:
def current_datetime(request):
    current_date = datetime.datetime.now()
    return render_to_response('current_datetime.html', locals())
直接使用与模板中的变量相同的名字命名临时变量current_date,调用的时候使用locals,它囊括了函数执行到该时间点定义的所有变量。
3、get_template()中使用子目录
t = get_template('dateapp/current_datetime.html')
由于 render_to_response() 只是对 get_template() 的简单封装, 你可以对 render_to_response() 的第一个参数做相同处理:
return render_to_response('dateapp/current_datetime.html', {'current_date': now})
4、include模板标签
该标签允许在模板中包含其他模板的内容。
{% include 'nav.html' %}
{% include "nav.html" %}
{% include 'includes/nav.html' %}

包含了以变量 template_name 的值为名称的模板内容:

{% include template_name %}

六、模板继承



模板继承就是先构造一个基础框架模板,而后在其子模板中对它所包含站点公用部分和定义块进行重载。
1、定义基础模板
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
<html lang="en">
<head>
    <title>{% block title %}{% endblock %}</title>
</head>
<body>
    <h1>My helpful timestamp site</h1>
    {% block content %}{% endblock %}
    {% block footer %}
    <hr>
    <p>Thanks for visiting my site.</p>
    {% endblock %}
</body>
</html>
2、修改模板使用该基础模板
修改current_datetime.html
{% extends "base.html" %}

{% block title %}The current time{% endblock %}

{% block content %}
<p>It is now {{ current_date }}.</p>
{% endblock %}
修改hours_ahead.html
{% extends "base.html" %}

{% block title %}Future time{% endblock %}

{% block content %}
<p>In {{ hour_offset }} hour(s), it will be {{ next_time }}.</p>
{% endblock %}
3、views.py
from django.shortcuts import render_to_response
import datetime

def current_datetime(request):
	now = datetime.datetime.now()
	return render_to_response('current_date.html',{'current_date': now})

def hours_ahead(request, hours_offset):
	try:
		hours_offset = int(hours_offset)
	except ValueError:
		raise Http404()
	next_time= datetime.datetime.now() + datetime.timedelta(hours=hours_offset)
	return render_to_response('hours_ahead.html', locals())
你可以根据需要使用任意多的继承次数。 使用继承的一种常见方式是下面的三层法:
  • 创建 base.html 模板,在其中定义站点的主要外观感受。 这些都是不常修改甚至从不修改的部分。
  • 为网站的每个区域创建 base_SECTION.html 模板(例如, base_photos.html 和 base_forum.html )。这些模板对 base.html 进行拓展,并包含区域特定的风格与设计
  • 为每种类型的页面创建独立的模板,例如论坛页面或者图片库。 这些模板拓展相应的区域模板。
这个方法可最大限度地重用代码,并使得向公共区域(如区域级的导航)添加内容成为一件轻松的工作。
以下是使用模板继承的一些诀窍:
  • 如果在模板中使用 {% extends %} ,必须保证其为模板中的第一个模板标记。 否则,模板继承将不起作用。
  • 一般来说,基础模板中的 {% block %} 标签越多越好。记住,子模板不必定义父模板中所有的代码块,因此你可以用合理的缺省值对一些代码块进行填充,然后只对子模板所需的代码块进行(重)定义。 俗话说,钩子越多越好。
  • 如果发觉自己在多个模板之间拷贝代码,你应该考虑将该代码段放置到父模板的某个 {% block %} 中。
  • 如果你需要访问父模板中的块的内容,使用 {{ block.super }}这个标签吧,这一个魔法变量将会表现出父模板中的内容。 如果只想在上级代码块基础上添加内容,而不是全部重载,该变量就显得非常有用了。
  • 不允许在同一个模板中定义多个同名的 {% block %} 。 存在这样的限制是因为block 标签的工作方式是双向的。 也就是说,block 标签不仅挖了一个要填的坑,也定义了在父模板中这个坑所填充的内容。如果模板中出现了两个相同名称的 {% block %} 标签,父模板将无从得知要使用哪个块的内容。
  • {% extends %} 对所传入模板名称使用的加载方法和 get_template() 相同。 也就是说,会将模板名称被添加到 TEMPLATE_DIRS 设置之后。
  • 多数情况下, {% extends %} 的参数应该是字符串,但是如果直到运行时方能确定父模板名,这个参数也可以是个变量。 这使得你能够实现一些很酷的动态功能。

你可能感兴趣的:(django,模板)