首页 > 代码库 > Django学习笔记(二)—— 模板
Django学习笔记(二)—— 模板
疯狂的暑假学习之 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}}