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}}