Django Template模板层 (下) ----------- 过滤器、人性化过滤器、模板继承、模板加载
---恢复内容开始---
- 过滤器
除了模板标签可以帮助我们对数据或者进行逻辑处理。django 中还提供了一款工具叫做过滤器,过滤器也可以实现一些模板变量的运算,判断或是其他逻辑处理。
-
- add
语法: {{ var1|add:var2 }}
add 过滤器可以实现 var1 与 var2 的相加,并且在遇到其他相同数据类型的,比如列表时,加号还可以重载为拼接功能
过滤器首先会将数据转换成Int类型,进行相加,如果转换失败,则会尝试使用 Python 中的数据类型
列表、元祖等这样的数据类型来进行转换,并且执行对应类型的加法
如果都转换失败,那么结果为一个空字符串
<p>add :{{ value|add:10 }}</p> <p>add :{{ list_1|add:list_2 }}</p>
-
- capfirst
语法: {{ var|capfirst }}
将变量第一个字母变为大写,如果第一个字符不是字母,过滤器不生效
<p>capfirst:{{ "Abc"|capfirst }}</p> <p>capfirst:{{ "1abc"|capfirst }}</p>
-
- center
语法: {{ value|center:"length" }}使 value 在给定的 length 范围内居中
<p>center: {{ "abc"|center:"10" }}</p>
-
- cut
语法: {{ value|cut:"str" }}
在 value 中移除所有 str
<p>cut: {{ "a*b*c"|cut:"*" }}</p>
-
- date
语法: {{ value|date:SHORT_DATE_FORMAT" }}
与 {% now %} 标签所使用格式字符一致; value 为一个 datetime 对象
输出最终格式与项目时区及语言设置有关
import datetime datetime = datetime.datetime.now()
<p>date: {{ datetime|date:"H:i" }}</p> <p>date: {{ datetime|date:"Y/m/d" }}</p>
-
- default
语法: {{ value|default:"默认值" }}
如果 value 值为假,则取"默认值",反之返回 value
<p>default: {{ 0|default:"这是展示的默认值" }}</p>
非空非0为真,0或空为假
-
- default_if_none
语法: {{ value|default_if_none:"默认值" }}
如果 value 值为 None ,则取"默认值",反之返回 value
<p>default_if_none: {{ None|default_if_none:"value值为None" }}</p> <p>default_if_none: {{ 0|default_if_none:"aaaa" }}</p>
-
- dictsort
语法: {{ value|dictsort:"attr" }}
value 为字典列表数据,列表中数据均为类字典数据: [ {1:'a'}, {2:'b'}, ]
根据给定 attr 值进行排序,一般是从小到大的顺序
sort_list_dict = [ {'name': '小绿', 'department': 'Development', 'age': 32}, {'name': '小红', 'department': 'Leader', 'age': 21}, {'name': '小飞', 'department': 'Test', 'age': 18}, {'name': '小落', 'department': 'Development', 'age': 15}, {'name': '大胖', 'department': 'Leader', 'age': 43} ]
<p>dictsort: </p> {% for var in sort_list_dict|dictsort:"age" %} <p> {{ var.name }} </p> {% endfor %}
-
- dictsortreversed
语法: {{ value|dictsortreversed:"attr" }}
与 dictsort 功能相同,但是排序方式与 dictsort 相反,从大到小
-
- divisibleby
语法: {{ value|divisibleby:num }}
如果给定的 value 可以被 num 整除,返回 True ;反之,返回 False
常用来做整除判断
<p>divisibleby: {{ 8|divisibleby:2 }}</p>
-
- escape
语法: {{ value|escape }}
将value值转义输出;
可以在取消转义autoescape标签下,选择性的打开某些需要转义的数据
{% autoescape off %}
{{ str_|escape }}
{{ str_ }}
{% endautoescape %}
-
- safe
语法: {{ value|safe }}
取消转义,与 {% autoescape off %} 标签意义相同
<p>{{ str_|safe }}</p>
-
- safeseq
语法: {{ value|safeseq }}处理一个包含标签字符串的列表数据,简单的 safe 是不行的,因为 safe 过滤器会把内容先整体处理为字符串;而不是依次过滤序列中的数据,而 safeseq 过滤器则会依次处理序列中的每一个
list_ = [ "<h1>第一个</h1>", "<h2>第二个</h2>", "<h3>第三个</h3>", ]
{{ list_|safe|join:"" }} <br> ------------------ <br> {{ list_|safeseq|join:"" }}
-
- filesizeformat
语法: {{ value|filesizeformat }}
格式化value值为人类可读的计算机存储单位。如:1 bytes、1.2 MB;
如果不是一个可以处理的数值类型,返回0。
最小单位为byte
<p>filesizeformat : {{ "1"|filesizeformat }}</p> <p>filesizeformat : {{ "3758331"|filesizeformat }}</p>
-
- first
语法: {{ value|first }}
返回序列数据 value 中的第一项
<p>first : {{ "abc"|first }}</p>
-
- last
语法: {{ value|last }}
返回序列数据 value 中的最后一项
<p>last : {{ "abc"|last }}</p>
-
- floatformat
语法: {{ value|floatformat:"精度" }}
设置浮点数 value 的精度,没有参数时,默认四舍五入保留小数点后一位
<p>floatformat : {{ "2.2332"|floatformat:"2" }}</p> <p>floatformat : {{ "2.2550"|floatformat:"2" }}</p> <p>floatformat : {{ "2.0000"|floatformat:"2" }}</p>
-
- join
语法: {{ value|join:"str" }}
将序列数据 value 通过 str 进行拼接
<p>join : {{ "abc"|join:"*" }}</p>
-
- length_is
语法: {{ value|length_is:"num" }}
判断序列 value 的长度是否为 num ,如果是,返回 True ,反之返回 False
<p>length_is : {{ "abc"|length_is:4 }}</p> <p>length_is : {{ "abcd"|length_is:4 }}</p>
-
- linebreaksbr
语法: {{ value|linebreaksbr }}
将字符串 value 中的所有换行符 \n 转换为 HTML 换行符 <br>
str_ = "abc\nbbb"
<p>linebreaksbr : {{ str_|linebreaksbr }}</p>
-
- linenumbers
语法: {{ value|linenumbers }}
显示 value 数据的行号,一般来说,是根据 value 字符串中的 \n 换行来确定每一行
str_ = "abc\nbb"
<p>linenumbers :<br> {{ str_|linenumbers }}</p> <p>linenumbers :<br> {{ str_|linenumbers|linebreaksbr }}</p>
-
- ljust
语法: {{ value|ljust:"num" }}
将字符串 value 按照给定宽度 num 左对齐
<p>ljust : {{"test"|ljust:"10" }}</p>
HTML中 空格是被忽略的,所以直观的我们并看不到这个过滤器的对齐效果,
需要使用   才可以在 HTML 中展示真正的空格效果,这个操作会在之后的自定义过滤器中为大家介绍。
-
- rjust
语法: {{ value|rjust:"num" }}
将字符串 value 按照给定宽度 num 右对齐
<p>rjust : {{ "test"|rjust:"10" }}</p>
-
- rjust
语法: {{ value|rjust:"num" }}
将字符串 value 按照给定宽度 num 右对齐
<p>rjust : {{ "test"|rjust:"10" }}</p>
-
- lower
语法: {{ value|lower }}
将字符串 value 中的全部字符串小写
<p>rjust : {{ "Aa123Bb"|lower }}</p>
-
- upper
语法: {{ value|upper }}
将字符串 value 中的全部字符串大写
<p>upper : {{ "Aa123Bb"|upper }}</p>
-
- title
语法: {{ value|title }}
将 value 字符串中每一个单词首字母大写,其余字符小写
<p>title : {{ "heLLO a12b world"|title }}</p>
-
- make_list
语法: {{ value|make_list }}
将 value 转换为列表
<p>make_list : {{ "a1好a2a"|make_list }}</p>
['a', '1', '好', 'a', '2', 'a']
-
- random
语法: {{ value|random }}
返回 value 序列中的一个随机值
<p>random : {{ "12345"|random }}</p>
-
- slice
语法: {{ value|slice:"start:stop:step" }}
与 Python 中序列切片用法类似,取出一定范围内的数据
<p>slice : {{ "abcdef"|slice:"0:5" }}</p> <p>slice : {{ "abcdef"|slice:"0:6" }}</p> <p>slice : {{ "abcdef"|slice:"0:6:2" }}</p>
-
- time
语法: {{ value|time:"time_format" }}
与 date 过滤器类似,但该过滤器只处理时、分、秒;
根据时间格式化字符输出时间,输出最终格式与项目时区及语言设置有关
import datetime datetime = datetime.datetime.now()
<p>time: {{ datetime|time:"H:i" }}</p> <p>time: {{ datetime|time:"Y/m/d" }}</p>
-
- timesince
语法: {{ start_time|timesince:end_time }}
计算从 start_time 一直到 end_time 的时间间隔, end_time 为可选,没有该值,截至从当前时间开始
分钟为返回最小单位
start_time = datetime.datetime(2019, 3, 3, 15)
end_time = datetime.datetime(2019, 3, 5, 17)
<p>time : {{ start_time|timesince:end_time }}</p <p>time : {{ start_time|timesince }}</p>
time : 2 days, 2 hours
time : 3 weeks, 2 days
-
- urlencode
语法: {{ value|urlencode }}
使用连接编码格式处理 value
<p>urlencode : {{ "http://example.com"|urlencode }}</p>
urlencode : http%3A//example.com
-
- urlize
语法: {{ value|urlize }}
使连接字符串 value 变为可点击的a标签连接
<p>urlize : {{ "http://example.com"|urlize }}</p> <p>urlize : {{ "http://example.com" }}</p>
- 人性化过滤器
除去上面所介绍的过滤器,django还提供了一个专门人性化处理数据的过滤器组件;
使用时,需要将'django.contrib.humanize'添加到 settings.py 文件中的 INSTALLED_APPS 属性中。
之后在模板页面加载 {% load humanize %} 就可以使用到 humanize 中的人性化过滤器。
-
- apnumber
语法: {{ value|apnumber }}
将整数转化为字符串,并按照语言设置返回对应的数字表示方式
<p>intcomma : {{ "3000"|intcomma }}</p> <p>intcomma : {{ "23300"|intcomma }}</p>
-
- intword
语法: {{ value|intword }}
将一个大型数字转换成友好的文字表达形式,适合超过 100万 的数字
<p>intword : {{ "310100100"|intword }}</p>
-
- naturalday
语法: {{ value|naturalday }}
返回value时间相对于今天。返回"今天","明天"或者"昨天"
today = datetime.datetime.now()
<p>naturalday : {{ today|naturalday }}</p>
-
- naturaltime
语法: {{ value|naturaltime }}
获得 value 与当前时间的时间间隔,并使用合适的文字来描述;
如果超过一天间隔,将会使用 timesice 过滤器格式
start_time = datetime.datetime(2019, 3, 3, 15)
<p>naturalday : {{ start_time|naturaltime }}</p>
- 自定义过滤器
虽然有了django给我们提供的这么多方便的标签和过滤器;
但是有些时候,还不能达成我们想要的功能,那么就需要我们自定义标签和过滤器
django默认的过滤器及标签文件夹:
django/template/defaultfilters.py
django/template/defaulttags.py
1. 在当前app下创建保存自定义标签及过滤器的文件夹,这个文件夹常命名为 templatetags
2. 为了支持该文件夹可以作为模块导入, templatetags 文件夹下创建 __init__.py 文件
3. 创建过滤器 xxxx.py 文件,文件名自定义
4. 过滤器文件头部必须包含名为 register 的全局变量,该变量是 template.Library 对象的实例
5. 自定义过滤器为一个 Python 函数,参数可以是 1-2 个
-
-
- 比如 {{ value|upper }} ,过滤器函数名为 upper ,参数为 value
-
注意:过滤器参数可以是一个字符串,也可以使类似列表的其他类型,参数可以设置默认值。另外需要注意的是模板中无法进行异常处理,过滤器一旦出现错误,将会引发服务器错误
6. 最重要的一步,所有编写完成的过滤器函数,都要记得:使用 register.filter() 函数将其注册为 Library
实例
-
-
- register.filter(name=None, filter_func=None) :注册过滤函数
-
name :一个字符串,表示过滤器在模板的使用名称
filter_func :编写好的过滤器函数
# app/templatetags/my_filter.py from django import template register = template.Library() def return_length(value): # 返回变量长度 return len(str(value)) register.filter("return_length",return_length)
<p>{{ 'abc'|return_length }}</p> <!-- 返回3 -->
此外:除了我们使用 register.filter 函数来对过滤器函数进行注册;
还可以将 register.filter 作为装饰器 @register.filter 来使用,可以更加方便的进行过滤器函数注册
from django import template register = template.Library() @register.filter(name="delete_space") def delete_space(value): # 去掉value数据中所有空格 return value.replace(" ","")
但是,这里有个问题,我们的过滤器经常期望处理的数据类型是一个字符串,但是以上过滤器如果在对数字类型进行处理时,会引发 'int' object has no attribute 'replace' ,这样的错误,那么需要我们对传入过滤器的value参数进行字符串转变的处理。
解决办法也很简单,大家可能想到了直接用字符串工厂函数去转换传入参数、但是这里有更加优雅安全的方式,通过 django.template.defaultfilter 模块下的 stringfilter 装饰器来对过滤器函数进行装饰
stringfilter 这个装饰器可以帮助我们把传入过滤器函数的参数转换为它的字符串值
from django.template.defaultfilters import stringfilter @register.filter(name="delete_space") @stringfilter def delete_space(value): return value.replace(" ","")
现在过滤器函数的 value 参数将会先被装饰器@stringfilter处理成对应的字符串类型之后才会被作为参数传递到过滤器函数 delete_space 中。
接下来通过这个过滤器处理一个非字符串类型也就不会在报错了。
- 自定义标签
标签要实现的功能可以比过滤器更加强大,可以支持接收更多参数!
基本使用语法 {% tag "arg1" "arg2" "arg3" ... %}
很多模板标签可以接收多个参数,字符串或者模板变量;并且可以将这些变量经过一系列处理之后返回一个字符串这样的标签我们可以通过django为我们提供的 simple_tag() 注册函数来进行编写,该函数来自于django.template.Library
同样的,编写自定义标签函数完成之后,也需要进行注册,也可以直接将 @simple_tag 作为装饰器使用注册
from django import template register = template.Library() @register.simple_tag(name="myUpper") def myUpper(value): # 将模板变量处理为纯大写的模板标签 return str(value).upper() # register.simple_tag(name="myUpper",func=myUpper)
-
-
- simple_tag() 函数在这里帮助我们做了如下工作:
-
1. 检查标签函数所需参数数量
2. 截掉参数中的引号,确保函数接收到的是一个普通的字符串
3. 截掉参数中的引号,确保函数接收到的是一个普通的字符串
如果我们希望标签函数可以访问到当前模板中其他全部的模板变量值;那么可以使用simple_tag(takes_context=True)参数
比如通过视图函数向模板返回了
value = '哈哈哈哈哈哈' return render(request, template, locals())
可以在自定义标签处通过 simple_tag(takes_context=True) 来进行视图函数中 content 值的获取;
但是还要注意的是,此时自定义标签函数参数位置第一个必须为 context
@register.simple_tag(takes_context=True) def get_context(context): value = context.get("value") return "获取到的模板变量:%s" % value
模板页面直接使用
<p>{% get_context %}</p>
- 模板继承
关于模板,经常重复的编写页面是一个非常痛苦的事情;
那么在 django 中也提供了一种非常舒服方便的方法,可以使新的模板页面来继承自一个已编写好的 html 页面实现复用,免去重复工作;这就是模板继承。
-
- block
页面的继承不能说全部都拿过来,有时候只需要已经编写好的页面某些部分
其他部分提前挖好一些坑,去填充不同内容
挖坑可以通过模板中的 {% block %} 标签
{% block name %}
预留区域,可供未来继承的页面覆盖
{% endblock name %}
设计一个可以被继承的父模板,我们经常叫做base.html
<!DOCTYPE html> <html> <head> <title> {% block title %} 父模板标题 {% endblock title %} </title> </head> <body> {% block top %} <h3>父模板</h3> {% endblock top %} {% block content %} <div>这里是父模板页面内容</div> {% endblock content %} </body> </html>
在这个页面中,我们设计了三个 block 标签块 title 、 content 以及 top ;
每一个块都可以被之后继承的页面所覆盖新的内容
-
-
- 继承页面使用 {% extends "base.html" %} 标签进行页面的继承,现在编写一个test.html
-
{% extends "base.html" %} {% block title %} 子模版 {% endblock title %} {% block top %} <h3>子模板</h3> {% endblock top %} {% block content %} <p>我是子模版</p> {% endblock content %} </body> {% block other %} 哈哈哈哈哈 这里的内容不会显示 父模板并没有这样的block块 {% endblock other%}
除了对应 block 标签内容被子模板修改,其余内容均默认使用父模板中的
-
-
- 注意:
-
如果父模板内有模板变量或者其他上下文数据,不会被子模板继承,但是子模板可以为父模板内的模板数据赋值
如果需模板中具有模板变量等上下文数据,只有放到 block 标签块内数据才会显示
子模板中修改父模板中并不存在的block块,子模板不会显示
- 模板加载
除了 {% extends %} 与 {% block %} 结合的方式可以继承一个父模板
我们还可以使用 {% include %} 一个新的标签进行模板加载, include 标签使用语法与 extends 类似
-
- include
现在新建一个html文件,名为 li.html ,用来写一个简单的列表
<ul> <li>吃饭</li> <li>睡觉</li> <li>玩耍</li> <li>{{ var }}</li> </ul>
在需要导入的页面中使用 {% include "li.html" %} 进行引入
{% extends "base.html" %} {% block title %} 子模版 {% endblock title %} {% block top %} <h3>子模板</h3> {% endblock top %} {% block content %} <p>我是子模版</p> {% include "li.html" %} {% endblock content %} </body>
被 include 引入的新模板,会在渲染完成之后添加到父模板所给定的对应 block 块中
与 extends 不同, extends 常用来控制整个模板的样式和效果;
而 include 更加细化,可以在一个模板内包含其他多个模板
如果 include 所包含的模板页面中有模板变量需要被填充,会在包含 include 的页面下进行渲染这种行为也好像是,把一个新的渲染好的 html 页面嵌入了进来一样
---恢复内容结束---