疯狂的暑假学习之 Django学习笔记(二)—— 模板
参考: 《The Django Book》 第四章
一、模板基础知识
1.模板是如何工作的
用 python manage.py shell 启动交互界面(因为manage.py 保存了Django的配置,如果直接python启动交互界面运行下面代码会出错)
输入下面代码
>>> from django import template
>>> t = template.Template('My name is {{name}}.')
>>> c = template.Context({'name':'zhengkai'})
>>> print t.render(c)
My name is zhengkai.
最后显示My name is zhengkai.
解释:
t = template.Template('My name is {{name}}.') 创建一个Template对象
c = template.Context({'name':'zhengkai'}) 创建一个Context对象,用来保存template对象中的映射关系。它的构造函数是一个字典。
t.render(c) t用c来渲染,返回一个Unicode对象
2. 变量
上面的例子中,context传递的是 简单字符串。然而,模板系统还可以处理更多的东西,如列表,字典,自定义的对象等。
列表:
>>> from django.template import Template,Context
>>> t = Template('Item 2 is {{ items.2 }}')
>>> c = Context({'items':['apples','bananas','carrots']})
>>> print t.render(c)
Item 2 is carrots
字典:
>>> person={'name':'Sally','age':'43'}
>>> t = Template('{{person.name}} is {{person.age}} years old.')
>>> c = Context({'person':person})
>>> print t.render(c)
Sally is 43 years old.
对象属性:
>>> import datetime
>>> d = datetime.date(2014,7,3)
>>> d.year
2014
>>> d.month
7
>>> d.day
3
>>> t = Template("The date is {{date.year}}/{{date.month}}/{{date.day}}.")
>>> c = Context({'date':d})
>>> print t.render(c)
The date is 2014/7/3.
对象方法:
>>> class A:
... def getName(self):
... return 'Sally'
...
>>> a = A()
>>> a.getName()
'Sally'
>>> t = Template('name is {{a.getName}}')
>>> c = Context({'a':a})
>>> print t.render(c)
name is Sally
对象方法注意:不用写(),也不可以写参数
多级深度嵌套:
>>> person={'name':'Sally','age':'43'}
>>> t = Template('{{person.name.upper}}')
>>> c = Context({'person':person})
>>> print t.render(c)
SALLY
3.如何处理无效变量
默认情况下,如果一个变量不存在,模板系统会把它展示为空,不做任何事情。
4. Context对象
Context对象 很像 字典,可以想字典一样进行添加删除
>>> c = Context({'name':'Sally'})
>>> c['name']
'Sally'
>>> c['age'] = '23'
>>> c['age']
'23'
>>> del c['age']
>>> c['age']
Traceback (most recent call last):
File "<console>", line 1, in <module>
File "/usr/lib64/python2.7/site-packages/django/template/context.py", line 56, in __getitem__
raise KeyError(key)
KeyError: 'age'
5.基本模板标签和过滤器
if / else
例子:
{%if today_is_weekend %}
<p>Welcome to the weekend!</p>
{% endif %}
{%if today_is_weekend %}
<p>Welcome to the weekend! </p>
{% else %}
<p> Get back to work. </p>
{% endif %}
判断 if 后面的变量是真还是假。 空列表 [],空元组 (),空字典 {},空字符串 '' ,0,None,False 都被认为是假
{%if %} 标签还接受 and、or 或者not
{%if athlete_list and coach_list %}
Both athletes and coaches are available
{% endif %}
和 not 一起
{%if athlete_list and not coach_list %}
There are some athletes and avsolutely not coaches.
{% endif %}
多个and连用或者多个or可以连起来用
{%if athlete_list and not coach_list and cheerleader_list%}
但是and 和 or 不可以 同时使用
如下面的是错误的
{%if athlete_list and coach_list or cheerleader_list%}
for
<ul>
{% for athlete in athlete_list %}
<li>{{althete.name}}</li>
{% endfor %}
</ul>
也可以加上{% empty %} 标签,当定义的列表为空时,运行{% empty %} 后的内容
<ul>
{% for athlete in athlete_list %}
<li>{{althete.name}}</li>
{% empty %}
<p>There are no athletes.</p>
{% endfor %}
</ul>
Django 不支持 continue,break
每个 {% for %} 循环 里 有一个forloop变量,它保存循环进度的信息。只能在循环中使用,{% endfor %}后就不能使用了
{{forloop.counter}} : 从1开始计数,表示当前循环的执行次数
{{forloop.counter0}} : 跟{{forloop.counter}} 差不多,但是是从0开始计数的
{{forloop.revcounter}} : 表示循环的剩余次数
{{forloop.revcounter0}} :从0开始计数的
{{forloop.first}} : 一个布尔值,如果 是第一次 循环 则为True 否者为 False
{{forloop.last}} : 一个布尔值,如果 是追后一次 循环 则为True 否者为 False
{{forloop.parentloop}}:是一个指向当前循环的上一击循环的forloop 对象的引用(在嵌套循环时)
ifequal / ifnotequal
{% ifequal %}像 {%if %} 但,是用来判断后面的2个变量是否相同。相同执行。
{%ifnotequal %} 与ifequal 相反,不同才执行
{% ifequal user currentuser%}
<h1>Welcome</h1>
{% endifequal %}
也可以加上{% else %} 标签
{% ifequal secton 'sitenews' %}
<h1>Site News</h1>
{%else%}
<h1>No News Here</h1>
{% endifequal %}
只有模板变量,字符串,整数,小树可以作为{% ifequal %}标签的参数
注解
Django模板的注解用 {# #}
例如
{# This is a comment #}
多行注解
使用 {% comment %} 标签
例如:
{% comment %}
This is a
multi-line comment.
{% endcomment %}
过滤器 |
例如
{{name|lower}}
将大写转化为小写
过滤器可以嵌套使用
如
{ {my_lsit|first|upper} }
有的过滤器有参数,
如
{bio|truncatewords:"30"}
显示变量bio前30个词
一些最为重要的过滤器
addslashes:添加反斜杠到任何反斜杠、单引号或者双引号前面。这在处理包含JavaScript的文本时是非常有用的。
date:阿里指定的格式字符串参数格式化date或者datetime对象
如
{{pub_date|date:"F j, Y"}}
length:返回变量的长度。对于列表,返回列表元素的个数。对于字符串,返回字符串中字符个数。(但是也可以用__len__()来返回长度)
二、在视图中使用模板
可以这样
from django.http import HttpResponse
from django.template import Template, Context
import datetime
def current_datetime(request):
now = datetime.datetime.now()
t = Template('<html><body>It is now {{current_date}}.</body></html>')
c = Context({'current_date':now})
html = t.render(c)
return HttpResponse(html)
但上面的代码,模板任然嵌入到Python中,改进:
from django.http import HttpResponse
from django.template import Template, Context
import datetime
def current_datetime(request):
now = datetime.datetime.now()
fp = open('/test/www/mysite/templates/mytemplate.html')
t = Template(fp.read())
c = Context({'current_date':now})
html = t.render(c)
return HttpResponse(html)
上面这样还是不够好,如果很容易发生read的IO异常,而且这里对文件的位置进行了硬编码。如果每个视图函数都用该技术,就要不断复制这些模板位置,而且还要带来大量的输入工作。
改进:为了减少模板加载调用过程及模板本身的沉余代码,Django 提供了一种使用方便且功能强大的API,用于从磁盘中加载模板。
首先,要用此模板加载API,首先必须将模板的位置告诉框架,
在setting.py 设置 TEMPLATE_DIRS这个变量
setting.py 添加
TEMPLATE_DIRS = (
'/test/www/mysite/templates',
)
view.py
from django.http import HttpResponse
from django.template import Template, Context
from django.template.loader import get_template
import datetime
def current_datetime(request):
now = datetime.datetime.now()
t = get_template('mytemplate.html')
c = Context({'current_date':now})
html = t.render(c)
return HttpResponse(html)
用到了get_template() 函数 (要from django.template.loader import get_template)它以模板名称为参数,在TEMPLATE_DIRS中定义的路径找出模板位置,返回Template对象。
如果找不到,会发出TemplateDoesNotExist异常。DEBUG=False时 ,不会看到任何错误提示。
上面view.py中用get_template() 函数,再用HttpResponse(),还是繁琐了,改进:使用 render_to_response()
from django.shortcuts import render_to_response
import datetime
def current_datetime(request):
now = datetime.datetime.now()
return render_to_response('mytemplate.html',{'current_date':now})
render_to_response() 有两个形参,第一个写,template的名称,第二个是写为了创建Context时的字典
如果你认为写字典太麻烦,可以用locals()代替如:
from django.shortcuts import render_to_response
import datetime
def current_datetime(request):
current_date = datetime.datetime.now()
return render_to_response('mytemplate.html',locals())
注意:变量名称改成了current_date, 因为 locals() 返回的字典是一个保存代码中,变量名称跟变量的字典,如果用前面代码中now名字,就不行了,变量名称必须跟模板中用的一样。 还有locale() 返回的字典除了 有 currnet_date 还有一些其他模板不需要的变量,可能会影响效率,要之间权衡用不用。
三、{% include %} 标签 和 模板继承{% extend %}
1.{% include %} 标签
{% include %} 标签 允许在模板中加入其他模板的内容 include 后面跟 要加载模板名称字符串,也可以是变量,查找位置就是TEMPLATE_DIRS设置的位置
例子:
mypage.html
<html>
<body>
{% inlucde 'includes/nav.html'%}
<title>{{title}}</title>
</body>
</html>
inclues/nav.html
<div id="nav">
You are in: {{ current_section }}
</div>
2.模板继承{% extend %}标签
{% include %} 标签 虽然能减少代码重复,但是有些情况也还是比较繁琐。要用到模板继承{% extend %}。{% extend %} 参数一般情况下是字符串,也可以用变量。
一般都是建立一个基础模板 base.html
如:
base.html
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
<html lang="en">
<head>
<title>{% block title %} {% endblock %}</title>
</head>
<body>
<h1>My helpful timestamp</h1>
{% block content%}{% endblock %}
{% block footer %}
<hr>
<p>Thanks for visiting my site.</p>
{% endblock %}
</body>
</html>
current_datetime.html
{% extends 'base.html' %}
{% block title %} The current time {% endblock %}
{% block content %}
<p>It is now {{ current_date }}.</p>
{% endblock%}
如果需要访问父模板中快内容,可以使用{{block.super}}