Django:模板系统_过滤器

过滤器

1、在模板中,有时候需要对一些数据进行处理以后才能使用。一般在Python中我们是通过函数的形式来完成的。而在模板中,则是通过过滤器来实现的

2、在Django中函数虽然能够在模板中执行,但是不能够传递参数,即不能使用圆括号的形式来传递参数。所以便有了过滤器

3、其实,过滤器就是函数。滤器使用的是"|"符号来使用。比如使用add过滤器,那么示例代码为:{{ value|add:"2" }}

4、过滤器其实就是一个函数,可以对需要传入参数的"函数"进行处理,并且还可以额外接收一个参数(过滤器最多只能有两个参数)

5、过滤器的作用:对变量进行过滤。在真正渲染出来之前,过滤器会根据功能处理好变量,然后得出结果后再替换掉原来的变量展示出来

6、过滤器可以使用参数,在过滤器名称后面使用冒号":"再加上参数。注意:使用参数的时候,冒号和参数之间不能有任何空格,一定要紧挨着


例1:

⑴编辑视图

⑵编辑模板

⑶访问


例1_1:
⑴编辑视图

⑵编辑模板

⑶访问

⑷视图函数中调用有参函数:视图在中的函数就是一般的Python函数

注:从上面例子可以看出
1、如果函数在定义的时候没有参数,那么在模板中是可以正常调用的。但如果函数需要传入参数,那么就不能在模板中时候函数(在模板中不能使用圆括号的形式传入参数)

2、上面例子中,在模板中调用函数的方式根前面介绍的:当字典值为一个类对象时的调用方式差不多,只是说为函数时,不需要实例化,也不需要使用点操作符。从这里也可以看出,当字典的值为一个类对象时,在调用其方法的时候也不能通过圆括号的形式传入参数(只能在实例化对象时,传入实例属性)

3、因此可以看出:在模板中使用函数的局限性很大,因此就有了过滤器(使用过滤器来代替模板中的函数)

4、要分清楚:是在模板中不能调用有参函数,在视图函数中是没有这个限制的(视图函数中就是普通的Python函数、脚本了)。比如上面这个例子通过两种方式都可以达到同样的额效果,只是说一个是在视图函数中进行处理的,一个是在模板中处理的
    ⑴有些情况下可能:视图函数中可以通过函数进行处理,但是在使用DTL模板进行显示的时候,模板不支持了。这个时候就只能在模板中进行处理了(下面date过滤器会有一个例子)

模板常用过滤器

add过滤器

1、实例代码为:{{ value|add:"2" }}

2、作用:将传进来的参数添加到原来的值上面。即add(value,"2")

3、这个过滤器会尝试将值和参数转换成整形后进行相加。如果转换成整形的过程中失败了,那么会将值和参数进行拼接:如果是字符串,那么拼接成字符串,如果是列表,就会拼接成一个列表

例2:
⑴编辑视图

⑵编辑模板

⑶访问

例2_1:
⑴编辑视图

⑵编辑模板

⑶访问

注:从上面例子可以看出
1、add过滤器是是进行相加还是进行拼接是有传入的参数类型决定的:能否转为整形

2、add过滤器前后的参数:可以直接为具体的数,也可以是由视图函数传递过来的变量

cut过滤器

移除值中所有指定的字符串。类似为Python中的replace(arhs,"")函数
    ⑴Python中的replace(str1,str2):表示将某一个字符串中的所有str2子字符串替换成str1字符串
    ⑵只是说在Python中replace()函数是替换,而DTL中的cut过滤器是直接移除

例3:
⑴编辑视图

⑵编辑模板

⑶访问

date过滤器

1、将一个日期按照指定的格式,格式化成字符串

2、在DTL模板语言中date过滤器有以下格式化符号:

格式化符号 描述
Y 年:Year, 4 位数字表示 '1999' 
y 年:year, 2 位数字表示 '99'
m 月:数字表示的月份,有前导零. '01' to '12'
n 月:数字表示的月份,无前导零 '1' to '12'
F 月:月份, 长文本格式. 'January' 
M 月:月份,3字母短文本格式. 'Jan' 
N 月:出版风格的月份缩写(django 扩展) 'Jan.', 'Feb.', 'March', 'May' 
d 日:每月第几天, 带前导零 '01' to '31' 
j 日:每月第几天, 无前导零 '1' to '31'
S 日:英语序数后缀,用于一个月的第几天,2个字符 'st', 'nd', 'rd' or 'th' 
g 小时, 12-小时制,没有前导零 '1' to '12' 
G 小时, 24-小时制,没有前导零 '0' to '23
h 小时, 12-小时制,有前导零 '01' to '12'
H 小时, 24-小时制,有前导零 '00' to '23' 
i 分钟. '00' to '59' 
s 秒数, 带有前导零的数字表示 '00' to '59' 
a 'a.m.' 或 'p.m.'
A AM' 或 'PM'. 'AM' 
D 每周第几天,3字母的字符串. 'Fri' 
f 时间, 12-小时制的小时和分钟数, 如果分钟数为零,则不显示.(django 扩展). '1', '1:30'
l 每周第几天,长文本格式. 'Friday' 
L 是否闰年. True or False 
O 与格林威治的时间差(以小时计) '+0200'
P 12小时制的小时分钟及'a.m.'/'p.m.' 分钟数若为零则不显示用字符串表示特殊 的时间点 'midnight'  'noon' (django扩展) '1 a.m.', '1:30 p.m.', 'midnight','noon', '12:30 p.m.' 
r RFC 822 格式的日期 . 'Thu, 21 Dec 2000 16:01:07+0200' 
t 给定月共有多少天. 28 to 31 
T 本机时区. 'EST', 'MDT' 
w 一周中的第几天,没有前导零的数字 '0' (Sunday) to '6' (Saturday) 
W ISO-8601 一年的第多少星期数, 一周从 星期一开始 1, 23 
z 一年中的第几天 . 0 to 365 
Z 以秒计的时区偏移量. 这个偏移量对UTC西部 时区总是负数,而对UTC东部时区则总是正数 -43200 to 43200

例4:
⑴编辑视图

⑵编辑模板

⑶访问

注:
这个例子中时间值的格式化就是在模板中完成的,视图函数中只是返回了一个时间值,时间值的格式化以及显示都是在模板中完成的


例4_1:为什么要有过滤器
⑴编辑视图

⑵编辑模板

⑶访问

注:从上面例子可以看出(自己的理解,有错请指正)
1、上面这个例子中的时间格式处理就是在视图函数中完成的,模板只是负责显示,显示什么样的格式也是视图函数决定的

2、某些数据虽然可以在视图函数中处理,但是在视图函数中进行处理后,再经过DTL模板渲染后,可能最终在网页上显示的结果与我们在视图函数中处理的结果不一致。因此这个时候就需要在模板中进行处理了(Python函数无法满足我们的处理要求时,可以在模板中进行处理)

3、前面说了过滤器也是一个函数,就相当于一个函数是写在视图中的,一个"函数"是写在模板中的。至于数据是需要在视图函数中处理(在视图函数中处理后再传给模板进行显示)还是在模板中进行处理进而显示,还是要根据实际情况来的

4、只是感觉在模板中处理还是有点局限性的,比如在模板中通过过滤器获取了一个值,但是没法把它赋值给一个变量,进而无法进一步使用获得的这个值
    ⑴Django视图:可以当做Python语言来理解
    ⑵Django的DTL模板:可以当做一门新的语言、语法来理解。DTL模板在与视图函数进行交互时,就需要更多的考虑模板语法是不是支持了
    ⑶如:在视图函数中访问字典的值的方式为:字典变量名["键名"],但是DTL模板语法中在访问字典中键的值就是:{{"键名"}}

 #在视图函数中访问字典的值的方式
    numberDict = {"time1":datetime.now(),
                  "time2":datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
                  "time3":datetime.strptime(str(datetime.now()),"%Y-%m-%d %H:%M:%S.%f"),
                  "time4":datetime.now().year,
                  "time":datetime.now().date().month
                  }
    print("视图函数中访问字典中的值:",numberDict["time1"])

    #在DTL模板中访问字典键的值
    <h3>{{ time1 }}</h3>
    <h3>{{ time2 }}</h3>
    <h3>{{ time3 }}</h3>
    <h3>{{ time4 }}</h3>

default过滤器

1、如果值是False,那么就可以使用default过滤器为其设置一个默认值(字典、列表、字符串等不为False时,就返回其本身的值)

2、比如空列表[]、空字符串""、空字典{}、None等这些在if判断中表示False,那么可以使用default过滤器为其设置一个默认值

例5:
⑴编辑视图

⑵编辑模板

⑶访问

注:
这个例子中:视图函数传递给模板的变量context字典中没有名为"number1"的键,因此在使用{{number1}}获取变量值的时候,获取到的是None。然后通过default过滤器将None的值设为默认值

例5_1:
⑴编辑视图

⑵编辑模板

⑶访问

注:
在DTL模板中还有一个叫"default_if_none"的过滤器,这个过滤器的使用方法与default过滤器一样,只是在使用范围上有点差距           1、如果值是None,那么就会使用default_if_none过滤器提供的默认值

       2、default过滤器是所有被评估为False的都会使用默认值,而default_if_none则只有这个值等于None时才会使用默认值

first、last过滤器

1、first过滤器:返回列表、元组、字符串中的第一个元素

2、last过滤器:返回列表、元组、字符串中的最后一个元素

3、需要注意的就是这两个过滤器只有一个参数(前面介绍的过滤器都是由两个参数的)

例6:
⑴编辑视图

⑵编辑模板

⑶访问

floatformat过滤器

使用四舍五入的方式格式化一个浮点类型
    ⑴如果这个过滤器没有传递任何参数,那么只会在小数点后保留一位小数
    ⑵如果小数后面全是0且为传递参数那么只会保留整数
    ⑶当然也可以传递一个参数,表示具体要保留几位小数

例7:
⑴编辑视图

⑵编辑模板

⑶访问

join过滤器

类似于Python中的join()函数:将列表、元组、字符串用指定的字符进行拼接

例8:
⑴编辑视图

⑵编辑模板

⑶访问

length过滤器

获取一个列表、元组、字符串的长度,相当于Python中的len()函数

例9:
⑴编辑视图

⑵编辑模板

⑶访问

lower过滤器

将值中的所有字符全部转为小写,类似于Python中的lower()函数

例10:
⑴编辑视图

⑵编辑模板

⑶访问

upper过滤器

将指定的字符串全部转为大写,类似于Python中的upper()函数

例10:
⑴编辑视图

⑵编辑模板

⑶访问

random过滤器

在给定的列表、字符串、元组中随机选择一个值。类似于Python中的random.choice()函数:从序列中获取一个随机元素

例11:
⑴编辑视图

⑵编辑模板

⑶访问

safe过滤器

1、标记一个字符串是安全的,即会关掉这个字符串的自动转义。跟我们前面学习的autoescape标签的功能差不多

2、如果value是一个不包含任何特殊字符串,比如<a>这种,那么以上代码就会把字符串正常的输入。如果value是一串HTML代码,那么以上代码就会把这个HTML渲染到浏览器中

例12:
⑴编辑视图

⑵编辑模板

⑶访问

slice过滤器

对列表、元组、字符串等序列进行切片操作。类似于Python中的"[ : ]"

例13:
⑴编辑视图

⑵编辑模板

⑶访问

striptags过滤器

删除字符串中所有的HTML标签

例14:
⑴编辑视图

⑵编辑模板

⑶访问

truncatechars过滤器

如果给定的字符串超过了过滤器指定的长度,那么就会进行切割,并且会拼接三个点来作为省略号
    ⑴计数是从1开始的(与Python切片中类似:切片是从0开始的)
    ⑵不会包括最后一个元素(与Python切片中类似:包左不包右)

例15:
⑴编辑视图

⑵编辑模板

⑶访问

truncatechars_html过滤器

与truncatechars过滤器类似,只是说在切割的时候不会切割HTML标签(标签对中的内容也会计数)

例16:
⑴编辑视图

⑵编辑模板

⑶访问

注:
1、在Django中的DTL模板中还有其他的一些过滤器,这里只是介绍了一些较常用的过滤器

2、从上面的例子中可以看出:
    ⑴模板中的过滤器其实也是函数,跟视图中的函数时差不多的,只是说一个是在模板中使用,一个是在视图中使用
    ⑵其实有些数据可以直接在视图函数中进行处理,处理后再经context参数传递给模板进行显示。当然也可以直接在模板中处理,在显示。它们最终结果可能是一样的,至于选择哪种方式还是要看实际情况的
    ⑶需要注意的是:过滤器"函数"的参数最多只能有2个,因如果要实现一个功能函数,且这个函数的参数会超过2两,那么就只能在视图函数中进行处理了(还有一点就是,我自己感觉在模板中经过滤器获得一个值后,是不能将这个值赋值给一个变量的)
    
    
    


自定义模板过滤器

1、虽然DTL给我们内置了很多好用的过滤器,但是有些时候还是不能满足我们的需求。因此Django给我们提供了一个接口,让我们可以自定义过滤器,来实现自己的需求

2、模板过滤器必须要放在应用程序app中,并且这个app必须要在INSTALLED_APP中进行了安装(注册)。然后再在这个app下面创建一个叫做templatetags的Python包,再在这个包下面创建一个Python文件用来存储自定义过滤器的代码,在创建了存储过滤器的文件后,接下来就是在这个文件中写过滤器了

3、过滤器实际上就是Python中的一个函数,只不过是把这个函数注册到了模板库中,以后在模板中就可以使用这个函数了。但是这个函数的参数是有限制的:
    ⑴第一个参数必须是这个过滤器需要处理的值(即为|标识符左边的那个参数)
    ⑵第二个参数可有可无,如果有,那么就表示在模板中可以传递参数。如果没有,就表示在模板中华不能传递参数
    ⑶并且过滤器的函数最多只能有两个参数

4、在写过过滤器后,在使用django.template.Libray对象将过滤器注册进模板库就可以了    

例16:自定义过滤器
⑴创建Python
    ①在任意应用程序APP下main创建一个Python包来存放过滤器文件:Python包的名字必须是templatetags
    ②该应用程序APP必须是已经注册、安装了的:在INSTALLED_APP中进行了安装


⑵编写过滤器函数代码并将代码注册到模板库中
    ①过滤器最多只能有两个参数(可以选择只传入被过滤的那个参数,也可以选择再传入其他一个参数)。过滤器的第一个参数永远是被过滤的那个参数(也就是竖线左边的那个参数)
    ②导入所需模块,使用template模块来注册自定义过滤器:from django import template
    ③实例化template模块下的Library()类
    ④使用实例对象下的filter( )函数来注册自定义过滤器:函数第一个参数是过滤器的名字(任意),第二个参数时过滤器需要调用的函数(注意这里函数名字后无小括号)


⑶编辑模板(视图函数忘截图了)
    ①在模板中使用自定义过滤器时,必须在HTML代码最前面导入所需的过滤器文件:{% load 过滤器文件名 %}
    


⑷访问

例16_1:实际需求

需求描述:朋友圈中好友在发朋友圈后,经常能看到例如刚刚、多少分钟之前、多少天之前的时间说明,如:

1、如果时间间隔在一分钟之类,那么就显示"刚刚"
2、如果时间间隔大于1分钟,小于1小时,那么就显示"XX分钟前"
3、如果时间间隔大于1小时,小于24小时,那么就显示"XX小时前"
4、如果时间间隔大于24小时,小于30天,那么就显示"XX天前"
5、否则就显示具体时间,1017/10/20 16:15

分析需求
1、这个需求一看就知道需要有两个时间参数值:一个发布朋友圈的实际,一个当前时间。对于传入的发布时间就是需要过滤的时间,当前时间可以直接获取不需要传入,因此该过滤器就只需要一个被过滤的参数

2、这个需求也可以直接在视图函数中处理后得到一个返回值,然后直接传给模板进行显示,只是说这里介绍的过滤器(在模板中通过过滤器进行处理和显示),因此就以过滤器为例了(视图函数中处理和过滤器处理,都差不多:只是使用地方不一样)
⑴编写过滤器函数代码并将代码注册到模板库中
    ①过滤器注册到模板库中除了使用:filter("过滤器名",函数名)外,还可以使用装饰器@register.filter()
    ②@register.filter():可以直接使用装饰器来注册过滤器,与前面的register.filter("greet",greet)作用一致。只是说这样使用装饰器的话:默认函数名就是过滤器名
    ③@register.filter("过滤器名"):使用装饰器的话,也可以指定过滤器名字:@register.filter("time"),在装饰器中传入过滤器的名字

⑴编辑过滤器代码

# -*- coding: utf-8 -*-
# @Time    : 2020/3/21 0021 12:51
# @Author  : 不怕猫的耗子A

from django import template
from datetime import datetime

register = template.Library()

#@register.filter():可以直接使用装饰器来注册过滤器,与前面的register.filter("greet",greet)作用一致。只是说这样使用装饰器的话:默认函数名就是过滤器名
#使用装饰器的话,也可以指定过滤器名字:@register.filter("time"),在装饰器中传入过滤器的名字
@register.filter("WeChatTime")
def timeCalculator(release_time):
    release_time = datetime.strptime(release_time, '%Y-%m-%d %H:%M:%S')#将字符串时间格式化为datetime对象
    now = datetime.now()
    if isinstance(release_time,datetime) ==False:
        return "传入时间格式错误:%s" % release_time

    elif release_time > now:
        return "输入时间错误:输入的时间为未来时间"

    else:
        # 计算两个datetime对象的时间差的总秒数
        second_diff = (now - release_time).total_seconds()
        if 0 <= second_diff <= 60:
            return "刚刚"
        elif 60 < second_diff <= 60*60:
            min = int(second_diff / 60)#使用int()取整
            #print(second_diff / 60)#如果不取整的话可能会是小数17.2652632
            return "%s分钟以前" % min

        elif 60*60 < second_diff <= 24*60*60:
            hours = int(second_diff / (60*60))
            return "%s小时以前" % hours

        elif 24*60*60 < second_diff <= 24*60*60*30:
            days = int(second_diff / (24*60*60))
            return "%s天以前" % days
        else:
            return "发布时间为:%s" % release_time


⑵编辑视图


⑶编辑模板


⑷访问


 

发布了9 篇原创文章 · 获赞 0 · 访问量 228

猜你喜欢

转载自blog.csdn.net/zh18380113164/article/details/105013601