模板基本由两个部分组成,一是HTML代码,二是逻辑控制代码。
逻辑控制的实现又基本由三个部分组成:
1. 变量的使用
{{ person_name }} #使用双大括号来引用变量
2. tag的使用
{% if ordered_warranty %} #使用大括号和百分号的组成来表示使用Django提供的
template tag
{% for item in item_list %}
<li>{{ item }}</li>
{% endfor %}
3. filter的使用
{{ ship_date|date:"F j, Y" }},ship_date变量传给data过滤器,data过滤器通过使用
"F j, Y"这几个参数来格式化日期数据。"|"代表类似Unix命令中的管道操作。
Template system不仅仅可以和view进行合作,也可以自己独立使用。
最基本的使用方法是:
1. 使用模板代码字符串作为参数,创建一个Template类
2. 创建模板代码中所需要的上下文Context对象,包含所需要的各个引用参数的值
3. 调用Template.render()方法,把template渲染成一个完整的字符串。
>>> from django import template
>>> t = template.Template(‘My name is {{ name }}.‘)
>>> c = template.Context({‘name‘: ‘Adrian‘})
>>> print t.render(c)
>>> My name is Adrian.
还可以在template代码中使用dict索引,然后在context传入所需要的dict
>>> 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.‘
还可以使用函数,不过只能使用无参数的函数
>>> from django.template import Template, Context
>>> t = Template(‘{{ var }} -- {{ var.upper }} -- {{ var.isdigit }}‘)
>>> t.render(Context({‘var‘: ‘hello‘}))
u‘hello -- HELLO -- False‘
还可以使用列表索引,但是item.-1是不被允许的
>>> 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.‘
以上的使用方法被称为Dot Lookup方法。
使用dot lookup的访问函数功能时,需要注意的问题:
1. 当在模板代码中执行的函数抛出异常时,会一直向上层传播,除非这个异常中有一个参数
silent_variable_failure=True; 这样的话,这个出错的函数信息就会被渲染成空字符串。
>>> class SilentAssertionError(AssertionError):
... silent_variable_failure = True
>>> class PersonClass4:
... def first_name(self):
... raise SilentAssertionError
>>> p = PersonClass4()
>>> t.render(Context({"person": p}))
u‘My name is .‘
2. 很明显,调用函数会产生一些不好的结果,安全漏洞之类的,如果你有一个BankAccout,
然后在模板中写成{{ account.delete }}, 这样在渲染的时候,你的账号就被删除了。。。。
所以要在修改一下你的delete函数
def delete(self):
# Delete the account
delete.alters_data = True#缩进没有问题,把delete看成一个对象,设置它的alters_data属性。
这样在渲染的时候,就会变成failed silent。
当在渲染的时候,简单的key值没有找到时,会failed silent,变成空字符串,而不是大动干戈的
报错。
>>> from django.template import Template, Context
>>> t = Template(‘Your name is {{ name }}.‘)
>>> t.render(Context())
u‘Your name is .‘
>>> t.render(Context({‘var‘: ‘hello‘}))
u‘Your name is .‘
Context对象也可以进行增删改值的操作。
>>> from django.template import Context
>>> c = Context({"foo": "bar"})
>>> c[‘foo‘]
‘bar‘
>>> c[‘newvariable‘] = ‘hello‘
>>> del c[‘foo‘]
>>> c[‘foo‘]
使用python manage.py shell启动python交互式命令行窗口与一般直接启动python自带的
交互式命令行窗口的区别是前者会通过找一个DJANGO_SETTINGS_MODULE环境变量,
告诉Django导入settings.py的配置信息。
基本的tag和filter的用法
tag:
可以使用and, or, not来组织你的逻辑。但不允许and和or同时出现的条件语句中。
没有{% elif %}这样的用法,只能用嵌套来实现多重if语句。
{% if athlete_list %}
<p>Here are the athletes: {{ athlete_list }}.</p>
{% else %}
<p>No athletes are available.</p>
{% if not coach_list %}
<p>Here are the coaches: {{ coach_list }}.</p>
{% endif %}
{% endif %}
用来循环一个list,还可以使用resersed关键字来进行倒序遍历,一般可以用if语句来先
判断一下列表是否为空,再进行遍历;还可以使用empty关键字来进行为空时候的跳转。
{% for athlete in athlete_list resersed %}
<li>{{ athlete.name }}</li>
{% empty %}
<p>There are no athletes. Only computer programmers.</p>
{% endfor %}
for tag还提供了一些内置参数来提供模板循环的信息。
1. forloop.counter 当前循环计数,从1开始
{% for item in todo_list %}
<p>{{ forloop.counter }}: {{ item }}</p>
{% endfor %}
2. forloop.counter0 当前循环计数,从0开始,标准索引方式
3. forloop.revcounter 当前循环的倒数计数,从列表长度开始
4. forloop.revcounter0 当前循环的倒数计数,从列表长度减1开始,标准
5. forloop.first bool值,判断是不是循环的第一个元素
6. forloop.last 同上,判断是不是循环的最后一个元素
7. forloop.parentloop 用在嵌套循环中,得到parent循环的引用,然后可以使用以上的参数
{% for country in countries %}
<table>
{% for city in country.city_list %}
<tr>
<td>Country #{{ forloop.parentloop.counter }}</td>
<td>City #{{ forloop.counter }}</td>
<td>{{ city }}</td>
</tr>
{% endfor %}
</table>
{% endfor %}
- ifequal和ifnotequal,一看就是直接比较值的tag,需要两个参数,用法比较有限,
- 只限于字符串,整数,小数的比较,什么列表,字典,元组不支持。
{% ifequal user currentuser %}
<h1>Welcome!</h1>
{% ifequal section "community" %}
<h1>Community</h1>
{% endifequal %}
{% endifequal %}
- {# #},模板中注释的用法,只能用在一行
- 如果要使用多行注释,要使用{% comment %}
{# This is a comment #}
{% comment %}
This is a
multi-line comment.
{% endcomment %}
filter:
filter用于变量在显示之前的一些简单的处理。使用类似管道的操作符"|",也可以进行链式操作
{{ name|lower }}
{{ my_list|first|upper }}
{{ bio|truncatewords:"30" }}
介绍几个重要的filter:
- addslashes :给任何的反斜线,单引号,双引号,再加一个反斜线。在文本中含有javascript字符串的时候有用。
- date :用来对data和datatime对象的字符串信息进行格式化。
- {{ pub_date|date:"F j, Y" }}
- length :返回变量的长度。
在view中使用template:
首先在settings.py中配置模板文件的路径。
TEMPLATE_DIRS = (
‘/home/django/mysite/templates‘,
)
记住一个路径的时候要使用逗号,这样是来区分是一个tuple还是一个block expression
也可以在设置的时候使用python文件路径操作代码:
import os.path
TEMPLATE_DIRS = (
os.path.join(os.path.dirname(__file__), ‘templates‘).replace(‘\\‘,‘/‘),
)
然后,可以在view中使用模板
from django.template.loader import get_template
from django.template import Context
from django.http import HttpResponse
import datetime
def current_datetime(request):
now = datetime.datetime.now()
t = get_template(‘current_datetime.html‘)
html = t.render(Context({‘current_date‘: now}))
return HttpResponse(html)
大多数情况下,你会使用一种shortcut方法,render_to_response()去完成以上的工作。
from django.shortcuts import render_to_response
import datetime
def current_datetime(request):
now = datetime.datetime.now()
return render_to_response(‘current_datetime.html‘, {‘current_date‘: now})
locals()的小技巧
如果你有很多变量要传给render,一个一个构造dict元素很麻烦。直接把变量名改成模板中所需要的变量名,
再使用locasl()函数,轻松搞定
def current_datetime(request):
current_date = datetime.datetime.now()
return render_to_response(‘current_datetime.html‘, locals())
locals()会返回局部空间中变量信息的dict,直接可以传给render,但有一点需要注意,它会返回把有的局部变量
信息,有一些可能不需要用到,如request变量。
{% include %}的使用
{% include ‘nav.html‘ %},用来引入其它模板的内容,减少重复的模板代码
{% include template_name %},还可以使用变量名
如果include的模板文件没有找到,当DEBUG为真时,会报错TemplateDoesNotExist,当为假时,页面那一块为
空白。
诚然,include可以有效减少模板的重复代码。但一种更优雅的方式是:
template inheritance.
首先,创建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 site</h1>
{% block content %}{% endblock %}
{% block footer %}
<hr>
<p>Thanks for visiting my site.</p>
{% endblock %}
</body>
</html>
我们使用一个新的tag,{% block %}用来告诉template engine,这个部分会被子模板
来实现。如果子模板没有实现这些部分,就会默认使用父模板的代码。
再看看,子模板要怎么写:
{% extends "base.html" %}
{% block title %}The current time{% endblock %}
{% block content %}
<p>It is now {{ current_date }}.</p>
{% endblock %}
只需要先使用{% extends %}继承父模板,再把相应需要实现的部分写上所需要的内容。
{% extends template_name %}也可以使用变量名来实现动态。
模板继承的三层继承策略:
1. 创建一个base.html,用来设置外观
2. 为网站的每一个部分,创建base_SECTION.html,比如base_phote.html, base_forum.html
3. 为每一个页面创建自己的模板。