# 模块层之标签、自定义标签
# 自带的标签
标签看起来像是这样的:
{% tag %}
。标签比变量更加复杂:一些在输出中创建文本,一些通过循环或逻辑来控制流程,一些加载其后的变量将使用到的额外信息到模版中。一些标签需要开始和结束标签 (例如{% tag %} ...标签 内容 ... {% endtag %})。for 遍列每个元素:(可以是字典、列表、类对象(通过.属性查询))
遍历一个对象列表/列表嵌套的字典 (不支持break)
#index视图函数 def index(request): person_list = [{'name':'赵丽颖'},{'name':'宋茜'},{'name':'霍思燕'}] return render(request, "index.html", {"person_list": person_list}) ------------------------------------------------ #修改index.html {% for person in person_list %} <p>{{ person.name }}</p> {% endfor %}
# 遍历一个列表
#修改index视图函数 def index(request): li = [123, 456, 567] return render(request, "index.html", {"li": li}) #render必须传字典参数 ------------------------------------ #修改index.html,修改body部分 #还可以用反序 {% for obj in list reversed %} <p> {% for item in li %} <span>{{ item }}</span> //标签 {% endfor %} </p>
遍历一个字典
//修改index.html,(在视图函数中,只要传入一个字典就可以了,名字必须为dic) {% for key,val in dic.items %}
:
{% endfor %} ```# 总结
for循环,循环一个列表 <ul> {% for name in name_list reversed %} <li>{{ forloop.counter }} {{ name }}</li> {% endfor %} </ul> 循环一个字典 <ol> {% for key,value in name_dict.items %} <li> {{ forloop.counter0 }} {{ key }} --- {{ value }} </li> {% endfor %} </ol> 不支持break等操作 if判断 结合过滤器的写法 {% if num|xxx:20 > 2000 %} <h2>大于2千</h2> {% else %} <h2>小于等于2千</h2> {% endif %}
注意:Django的模板语言中属性的优先级大于方法(了解)
def xx(request): d = {"a": 1, "b": 2, "c": 3, "items": "100"} return render(request, "xx.html", {"data": d}) #如上,我们在使用render方法渲染一个页面的时候,传的字典d有一个key是items并且还有默认的 d.items() 方法,此时在模板语言中: {{ data.items }} #默认会取d的items key的值。
总结Django的标签:
1、if 标签 # 判断标签 2、for 标签 # 循环标签 3、with 标签 # 起别名标签 4、crsf_token 标签 # 防止跨站请求伪造
# 自定义过滤器
举例:添加一个乘法过滤器
第一步:
1、修改settings.py中的INSTALLED_APPS,最后一行添加当前的app。不然找不到app下面的模块。 2、在app项目目录下新建一个templatetags目录(目录必须是这个,否则找不到) 3、在新建的templatetags目录下新建一个my_filter_tag.py(这个可以随便起,最好不要使用'_') 4、自定义过滤器的第一个参数可以是变量/参数,第二个参数必须是参数,不能是变量
对my_filter_tag.py 进行修改,内容如下
from django import template from django.utils.safestring import mark_safe # 这个相当于django自带的safe,因为自定义的标签不能使用自带的safe,只能用他 register=template.Library() #导入模块注册表 @register.filter #增加@register.filter,是为了将函数转换成过滤器。函数的名字,可以自定义 def multi_filter(x,y): #过滤器的函数默认接受两个参数 return x*y @register.filter(name=multi) # 重命名,以后使用就用它multi def multi_filter(x,y): return x*y
# 第二步:
在响应使用自定义过滤器的html文件中,开始就应该导入
#要过滤的html {% load my_filter_tag %} //其实类似于加载导入,p标签中的内容,是执行了multi_filter过滤器。 <p>{{ num|multi_filter:5 }}</p> ------------------------------------------------------------- #views.py文件 def index1(request): num = 100 return render(request, 'login.html', {'num': num}) -------------------------------------------------------------- #url.py文件 urlpatterns =[ url(r'^app/index/$',views.index1) ]
注意:其实此时 就是在执行multi_filter过滤器,且默认此函数接受两个参数,第一个:num(即要被过滤的对象);第二个:5(即要用于参与处理的参数)。(这里的num、5相对于函数x,y). 重启项目即可
# 注意:
如果要完成3位乘法呢?过滤器可以增加一个形参,但是index.html怎么加第3个参数呢? 答:是,它不能加第3个参数。所以只能在后端,将参数形式修改列表,元组,字典等方式,就可以了。 比如:第二个参数,可以传入字符串,然后进行切割,然后再返回。
举例:计算4*5*6
修改index视图函数
def index(request): num1 = 4 num2 = 5 num3 = 6 num_list = [num1,num2,num3] return render(request,'index.html',{'num_list':num_list})
修改my_filter_tag.py 中的过滤器
@register.filter def multi_filter(num_list): res = 1 for i in num_list: res*=i return res
修改index.html, 修改body部分
{% load my_filter_tag %} <p>{{ num_list|multi_filter }}</p> //默认multi_filter前的num作为第一个参数传入,要是后面有:传入的是第二个参数
举例: 通过过滤器返回html标签,按照原来的写法只会返回一个文本(存在的问题:因为防止XSS攻击)
因为django遇到html或者js标签,会转义。它认为是不安全的!那么如何告诉它,是安全的呢?
需要在过滤器中导入make_safe模块
修改my_filter_tag.py文件中的link_tag过滤器,完整代码如下:
#使用make_safe方法,告诉django是安全的,不需要转义 from django import template from django.utils.safestring import mark_safe register=template.Library() @register.filter def multi_filter(num_list): res = 1 for i in num_list: res*=i return res @register.filter def link_tag(href): return mark_safe("<a href=%s>click</a>" % href) #告诉浏览器这个标签安全
修改index.html
{% load my_filter_tag %} <p>{{ link|link_tag }}</p>
重启django项目,因为网页有缓存,懒得清理了
# 自定义标签
标签:是为了做一些功能,把标签当作函数使用
调用标签,使用的方法:{% 标签过滤器名 参数1,参数2,参数3... %} 参数不限,但不能放在if for语句中
修改my_filter_tag.py,增加multi_tag函数
@register.simple_tag #表示将函数转换为自定义标签 def multi_tag(x,y,z): return x*y*z @register.simple_tag def join_str(*arg,**kwargs): #要求传入的参数是(位置参数,关键字参数) return 'xxx'
修改index.html,修改body部分
{% load my_filter_tag %} <p>{% multi_tag 7 8 9 %}</p> //传递参数 <p>{% join_str 7 8 9 k1=3 k2=4%}</p> //多种参数
总结:
1、自定义标签和自定义过滤器的区别: 1. 标签,是为了做一些功能。过滤器,是对斜杠前面的数据做过滤。 2. 标签可以写任意个形参,而过滤器最大只能写2个形参。如果过滤器需要接收多个参数,需要将参数存放在列表,元组,字典等数据中。 3. 过滤器可以用在if等语句后,标签不可以 #综合案例: #自定义模块文件my_tags.py中 from django import template from django.utils.safestring import mark_safe register = template.Library() #register的名字是固定的,不可改变 @register.filter def filter_multi(v1,v2): return v1 * v2 @register.simple_tag #和自定义filter类似,只不过接收更灵活的参数,没有个数限制。 def simple_tag_multi(v1,v2): return v1 * v2 @register.simple_tag def my_input(id,arg): result = "<input type='text' id='%s' class='%s' />" %(id,arg,) return mark_safe(result) # 在使用自定义simple_tag和filter的html文件中导入之前创建的 my_tags.py {% load my_tags %} # 使用simple_tag和filter(如何调用) {% load xxx %} # num=12 假如这里再视图函数中传入了num=12 {{ num|filter_multi:2 }} # 24 {{ num|filter_multi:"[22,333,4444]" }} {% simple_tag_multi 2 5 %} 参数不限,但不能放在if for语句中 {% simple_tag_multi num 5 %} #注意:filter可以用在if、for等语句后,simple_tag不可以,也就是说自定义不可以使用这些 {% if num|filter_multi:30 > 100 %} {{ num|filter_multi:30 }} {% endif %}
inclusion_tag: 区别于组件,此方法使某个部件可以动态更换效果,如:分页
多用于返回html代码片段:其实是一个函数标签,可以将加载数据传给装饰器的html文件,然后将渲染后的html文件当作组件返回给加载对象(这个装饰器,register.inslusion_tag会将渲染好的html文件返回给调用者)
第一步:通过视图函数返回数据给装饰器函数,以便渲染;第二步:通过装饰器函数的html进行渲染;第三步:返回渲染好的html片段,插入到最终的html代码中。(其实就是返回了个组件)
在templatetags/my_inclusion.py中 (过滤器需要触发的标签)
from django import template # 可以写成 from django.template import Library register = template.Library() @register.inclusion_tag('result.html') #将result.html里面的内容用下面函数的返回值渲染,然后作为一个组件一样,加载到使用这个函数的html文件里面 def show_results(n): #参数可以传多个进来 n = 1 if n < 1 else int(n) data = ["第{}项".format(i) for i in range(1, n+1)] return {"data": data} #这里可以穿多个值,和render的感觉是一样的{'data1':data1,'data2':data2....}
第二步:在templates/snippets/result.html (函数提交数据进行渲染的html,其实就是返回了一个组件给调用标签的位置)
<ul> {% for choice in data %} <li>{{ choice }}</li> {% endfor %} </ul>
在templates/index.html中(调用标签的html)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="x-ua-compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>inclusion_tag test</title> </head> <body> {% load my_include %} // 先加载自定义文件名 {% show_results 10 %} //调用函数返回组件 </body> </html>
总结:
{% load 函数名 %} #用于加载视图函数 {% extend 'xxx.html' %} #用于加载模块 {% include 'xxx.html' %} #用于加载组件文件
# 练习:
1、使用过滤器完成加减乘除的操作:
{{a|add:b}} #加法、减法可以将b传入负数,但是不能-b
#乘法
@register.filter
def multiy(x,y):
return x*y
{{a|multiy:b}}
#给一个网站和文字,使它能是一个可以跳转的标签
#法一:
@register.filter
def show_a(x,y):
return '<a href="{}">{}</a>'.format(x,y)
{{a|show_a:'百度'|safe}}
2、面试题:模块中使用{% sqr_list 3 %},生成如下dropdown list控件(下拉菜单)
# 在 templatetags/my_tag.py文件中
from django import template
register = template.Library()
@register.inclusion_tag('result.html')
def show_a(n):
dic = {}
for num in range(n):
dic.update(dict([(num,num*num),]))
return {'data':dic}
---------------------------------------------
#result.html文件中
<div class="dropdown">
<button id="dLabel" type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
Dropdown trigger
<span class="caret"></span>
</button>
<ul class="dropdown-menu" aria-labelledby="dLabel">
<li> key    text</li>
{% for key,values in data.items %}
<li> {{ key }}     {{ key }}的平方是{{ values }}</li>
{% endfor %}
</ul>
</div>
----------------------------------------------
# views.py文件中
def show_a(request):
return render(request,'base.html')
-----------------------------------------------
#base.html文件中
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
{% load static %}
<link rel="stylesheet" href="{% get_static_prefix %}bootstrap-3.3.7-dist/css/bootstrap.min.css">
</head>
<body>
<div class="container">
{% load my_tags %}
{% show_a 10 %}
</div>
<script src="{% get_static_prefix %}js/jquery-3.4.1.js"></script>
<script src="{% get_static_prefix %}bootstrap-3.3.7-dist/js/bootstrap.min.js"></script>
</body>
</html>