python后台架构Django教程之templates模板
每一个Web框架都需要一种很便利的方法用于动态生成HTML页面。 最常见的做法是使用模板。
模版是纯文本文件,可以生成任何基于文本的文件格式,比如HTML,XML,CSV等。
模板包含所需HTML页面的静态部分,以及一些特殊的模版语法,用于将动态内容插入静态部分。
本节就来了解这些特殊的模版语法。
前面我们在views视图函数中学习了可以使用render函数、render_to_response等函数返回静态html模板视图、或将字典参数传递给模板视图,渲染动态html模板视图。
一个简单的渲染模板示例如下:
from django.shortcuts import render_to_response from .models import User,Diary # findalluser将数据库内存储的数据读出并展示出来。 def findalluser(request): allpeople = User.objects.all() # 查询所有用户 dict={ 'people_list':allpeople } return render_to_response("showuser.html",dict) # 返回文件响应,第二个参数必须为字典
findalluser将数据库内存储的数据读出并结合html文件渲染出最后的响应hhtml源代码。这和jsp中的原理相同,python先将html文件的内容全部加载到内存中,再根据python的语法和传来的数据库数据生成html文件中python代码部分产生的文本,再将最终生成的html源代码返回到前端。
配置引擎
模板引擎通过settings.py文件中的TEMPLATES设置来配置。
搜索过程
当我们在views的视图函数中加载、搜索模板时,如下
get_template('detail.html')
Django将按以下顺序查找story_detail.html:
/home/html/example.com/detail.html('django'引擎) /home/html/default/detail.html('django'引擎) /home/html/jinja2/detail.html('jinja2'引擎)
当我们有多个app,并且在多个app下有相同模板名称时,例如
app1/templates/detail.html
app2/templates/detail.html
无论我们在哪个app的视图函数中搜索“detail.html”这个模板,都将只能搜索到第一个detail模板。所以我们要通过路径来区分模板。将文件目录构建成
app1/templates/app1/detail.html
app2/templates/app2/detail.html
这样我们在视图函数使用”app2/detail.html”的路径就能搜索不同app下的模板。
基本语法
1、模板上下文
views视图函数传递给模板的只能是字典参数。这个字典参数被称为模板的上下文context。比如:
render_to_response("showuser.html",{'key1':'value1','key2':object2})
在模板文件中可以直接通过键key来获取调用值value。比如下面的代码就表示字符串'value1'
{{ key1}}
模板能够访问到的不仅仅是对象的属性(比如字段名称)和视图中传入的变量,还可以执行对象的方法。
比如QuerySets提供了count()方法来计算含有对象的总数。
{{ users.count }}
你可以像这样获取所有关于当前用户集合的数目
2、变量
变量看起来就像是这样: {{ variable }}。
当模版引擎遇到一个变量,它将从上下文context中获取这个变量的值,然后用值替换掉它本身。
当模版系统遇到点(“.”),它将以这样的顺序查询这个圆点具体代表的功能:
字典查询(Dictionary lookup) 属性或方法查询(Attribute or method lookup) 数字索引查询(Numeric index lookup)如果你使用的变量不存在,模版系统将插入string_if_invalid选项的值,默认设置为”(空字符串)。
注意:像{{ foo.bar }}这种模版表达式中的“bar”,如果在模版上下文中存在,将解释为一个字面意义的字符串而不是使用变量bar的值 。
3、过滤器
过滤器的形式:
过滤器看起来是这样的:{{ name|lower }}。使用管道符号(|)来应用过滤器。该过滤器将文本转换成小写。
多级过滤器:
{{ text|escape|linebreaks }}就是一个常用的过滤器链,它首先转移文本内容,然后把文本行转成
标签。
过滤器带参:
{{ list|join:”, ” }}。使用逗号和空格去连接一个列表中的元素
过滤器的作用是对变量进行预处理,相当于函数的功能,过滤器的工作都可以在views视图函数中完成。也可以通过自定义函数来实现自定义过滤器。在后面的自定义过滤器中我们会了解。
例1、default
为false或者空变量提供默认值,像这样:
{{ value|default:"nothing" }}
例2、length
返回值的长度。它对字符串和列表都起作用。
{{ value|length }}
如果value是[‘a’, ‘b’, ‘c’, ‘d’],那么输出4。
为模版过滤器提供参数的方式是:过滤器后加个冒号,再紧跟参数,中间不能有空格!
目前只能为过滤器最多提供一个参数!
过滤器 | 说明 |
---|---|
add | 加法 |
addslashes | 添加斜杠 |
capfirst | 首字母大写 |
center | 文本居中 |
cut | 切除字符 |
date | 日期格式化 |
default | 设置默认值 |
default_if_none | 为None设置默认值 |
dictsort | 字典排序 |
dictsortreversed | 字典反向排序 |
pisibleby | 整除判断 |
escape | 转义 |
escapejs | 转义js代码 |
filesizeformat | 文件尺寸人性化显示 |
first | 第一个元素 |
floatformat | 浮点数格式化 |
force_escape | 强制立刻转义 |
get_digit | 获取数字 |
iriencode | 转换IRI |
join | 字符列表链接 |
last | 最后一个 |
length | 长度 |
length_is | 长度等于 |
linebreaks | 行转换 |
linebreaksbr | 行转换 |
linenumbers | 行号 |
ljust | 左对齐 |
lower | 小写 |
make_list | 分割成字符列表 |
phone2numeric | 电话号码 |
pluralize | 复数形式 |
pprint | 调试 |
random | 随机获取 |
rjust | 右对齐 |
safe | 安全确认 |
safeseq | 列表安全确认 |
slice | 切片 |
slugify | 转换成ASCII |
stringformat | 字符串格式化 |
striptags | 去除HTML中的标签 |
time | 时间格式化 |
timesince | 从何时开始 |
timeuntil | 到何时多久 |
title | 所有单词首字母大写 |
truncatechars | 截断字符 |
truncatechars_html | 截断字符 |
truncatewords | 截断单词 |
truncatewords_html | 截断单词 |
unordered_list | 无序列表 |
upper | 大写 |
urlencode | 转义url |
urlize | url转成可点击的链接 |
urlizetrunc | urlize的截断方式 |
wordcount | 单词计数 |
wordwrap | 单词包裹 |
yesno | 将True,False和None,映射成字符串‘yes’,‘no’,‘maybe’ |
4、标签
标签看起来像是这样的: {% tag %}。
标签比变量复杂得多,有些用于在输出中创建文本,有些用于控制循环或判断逻辑,有些用于加载外部信息到模板*以后的变量使用。
一些标签需要开始和结束标签(即 {% 标签 %} … 标签 内容 … {% ENDTAG %})。
Django自带了大约24个内置的模版标签。下面是一些常用的标签
1. for循环标签
- {% for user in people_list %}
- {{ user.username }}
- {% endfor %}
for循环中可以通过forloop.counter来获取你当前循环的次数。forloop.counter是DJango模板系统专门提供的一个变量,一般用来给循环项目添加有序数标。
2. if,elif和else标签
{% if athlete_list %} Number of athletes: {{ athlete_list|length }} {% elif athlete_in_locker_room_list %} Athletes should be out of the locker room soon! {% else %} No athletes. {% endif %}
需要注意,大多数模版过滤器都返回字符串类型,所以在if标签中使用过滤器做整数类型的比较通常是错误的,但length是一个例外。
3. autoescape
控制自动转义是否可用。参数是on或off。 该标签会以一个endautoescape作为结束标签.
{% autoescape on %} {{ body }} {% endautoescape %}
4. block
block标签可以被子模板覆盖。
5. comment
在{% comment %}和{% endcomment %}之间的内容会被忽略,作为注释。
比如,当要注释掉一些代码时,可以用此来记录代码被注释掉的原因。
例如:
Rendered text with {{ pub_date|date:"c" }}
{% comment "Optional note" %}Commented out text with {{ create_date|date:"c" }}
{% endcomment %}6. csrf_token
这个标签用于跨站请求伪造保护。常用于为form表单提供csrf令牌。
7. cycle
每当这个标签被访问,返回它的下一个元素。第一次访问返回第一个元素,第二次访问返回第二个参数,以此类推. 一旦所有的变量都被访问过了,就会回到最开始的地方,重复下去。这个标签在循环中特别有用:
{% for o in some_list %} ... {% endfor %}
第一次迭代产生的HTML引用了row1类,第二次则是row2类,第三次又是row1 类,如此类推。
也可以使用变量, 例如,如果你有两个模版变量:rowvalue1和rowvalue2, 可以让他们的值像这样替换:
{% for o in some_list %} ... {% endfor %}
在某些情况下,可能需要连续引用一个当前循环的值,而不前进到下一个循环值。要达到这个目的,只需使用as来给{% cycle %}取一个别名,就像这样:
... ... ... ...
将输出:
... ... ... ...
8. debug
输出整个调试信息,包括当前上下文和导入的模块。
9. filter
通过一个或多个过滤器对内容过滤。需要结束标签endfilter。
例如:
{% filter force_escape|lower %} This text will be HTML-escaped, and will appear in all lowercase. {% endfilter %}
10. include
加载指定的模板并以标签内的参数渲染。这是一种引入别的模板的方法,一定要将include和extend区分开!include类似Python的import。
{% include "http://blog.csdn.net/luanpeng825485697/article/details/foo/bar.html" %} 也可以使用变量名template_name: {% include template_name %}
11. spaceless
删除HTML标签之间的空白,包括制表符和换行。
{% spaceless %}
{% endspaceless %}五、注释
要注释模版中一行的部分内容,使用注释语法:{# #}。
{# {% if foo %}bar{% else %} #}
以上是单行注释(在{# …. #}中,不允许有新行)。
如果需要注释掉模版中的多行内容,请使用comment标签。
七、自动转义HTML
默认情况下,Django中的每个模板会自动转义每个变量。依次来避免跨站脚本攻击(Cross Site Scripting)(XSS)。也就是说,下面五个字符将被转义:
<会转换为< >会转换为> '(单引号)转换为' "(双引号)会转换为" &会转换为&但是,有时,模板变量含有一些你打算渲染成原始HTML的数据,你并不想转义这些内容。 例如,你可能会在数据库中储存一些HTML代码,并且直接在模板中嵌入它们。或者,你可能使用Django的模板系统来生成不是HTML的文本 – 比如邮件信息。要怎么办呢?
对于单个变量:
使用safe过滤器来关闭变量上的自动转义:
This will be escaped: {{ data }} This will not be escaped: {{ data|safe }}
对于模板块:
要控制模板上的自动转义,将模板(或者模板中的特定区域)包裹在autoescape标签中,autoescape标签接受on或者off作为它的参数。像这样:
{% autoescape off %} This will not be auto-escaped: {{ data }}. Nor this: {{ other_data }} {% autoescape on %} Auto-escaping applies again: {{ name }} {% endautoescape %} {% endautoescape %}
过滤器的字符串参数不自动转义
过滤器的参数可以是字符串,所有这种字符串参数在插入模板时都不会进行任何自动转义,所以需要程序员自己转义。
{{ data|default:"3 < 2" }} {# 正确的做法#} {{ data|default:"3 < 2" }} {# 错误的做法#}
使用自定义标签和过滤器
一、前置步骤
第一步,在app中新建一个templatetags包(名字固定,不能变,只能是这个),和views.py、models.py等文件处于同一级别目录下。这是一个包!不要忘记创建__init__.py文件以使得该目录可以作为Python的包。
在添加templatetags包后,需要重新启动服务器,然后才能在模板中使用标签或过滤器。
将你自定义的标签和过滤器将放在templatetags包下的一个模块里。
这个模块的名字是后面载入标签时使用的标签名,所以要谨慎的选择名字以防与其他应用下的自定义标签和过滤器名字冲突,当然更不能与Django内置的冲突。
假设你自定义的标签/过滤器在一个名为poll_extras.py的文件中,那么你的app目录结构看起来应该是这样的:
app1/ __init__.py models.py templatetags/ __init__.py poll_extras.py views.py
为了让{% load xxx %}标签正常工作,包含自定义标签的app必须在INSTALLED_APPS中注册。然后你就可以在模板中像如下这样使用:
{% load poll_extras %}
在templatetags包中放多少个模块没有限制。只需要记住{% load xxx %}将会载入给定模块名中的标签/过滤器,而不是app中所有的标签和过滤器。
要在模块内自定义标签,首先,这个模块必须包含一个名为register的变量,它是template.Library的一个实例,所有的标签和过滤器都是在其中注册的。 所以把如下的内容放在你的模块的顶部:
from django import template register = template.Library()
二、自定义模板过滤器
1、 编写过滤器
自定义过滤器就是一个带有一个或两个参数的Python函数:
注意:这个Python函数的第一个参数是你要过滤的对象,是必须要有的,第二个参数才是你自定义的参数。而且最多总共只能有两个参数,所以你只能自定义一个参数!这是过滤器的先天限制。
变量的值:不一定是字符串形式。 参数的值:可以有一个初始值,或者完全不要这个参数。例如,在{{ var|foo:”bar” }}中,foo过滤器应当传入变量var和参数”bar”。
由于模板语言没有提供异常处理,任何从过滤器中抛出的异常都将会显示为服务器错误。
下面是一个定义过滤器的例子:
def cut(value, arg): """将value中的所有arg部分切除掉""" return value.replace(arg, '')
下面是这个过滤器的使用方法:
{{ somevariable|cut:"0" }}
2、注册过滤器
一旦你写好了过滤器函数,就需要注册它,方法是调用register.filter,比如:
@register.filter(name='cut') def cut(value, arg): return value.replace(arg, '') @register.filter def lower(value): return value.lower()
三、自定义模板标签
标签比过滤器更复杂,因为标签可以做任何事情。Django提供了大量的快捷方式,使得编写标签比较容易。 对于我们一般的自定义标签来说,simple_tag是最重要的,它帮助你将一个Python函数注册为一个简单的模版标签。