模板介绍
在刚刚介绍完的视图层中我们提到,浏览器发送的请求信息会转发给视图函数进行处理,而视图函数在经过一系列处理后必须要有返
回信息给浏览器。
如果我们要返回html标签、css等数据给浏览器进行渲染,我们可以在视图函数中直接将HTML代码放到视图函数里,然后进行返回,这可以使我们很直观地看清楚浏览器从发送请求到看到前端界面内容的这个过程中视图函数的基本工作原理,但是这种将前端代码与后端代码耦合到了一起开发方式,会存在以下问题
基于上述原因,将前端页面和Python的代码分离是一种不错的开发模式。 为此
Django专门提供了模板系统
(Template System,即
模板层)来实现这种模式,这就是本章要具体讨论的问题。
一、模板语法传值
{{}}:变量相关
{%%}:逻辑相关
在views中我们写下几个变量来测试模板语法传值是否可行
def index(request): # 模版语法可以传递的后端python数据类型 n = 123 f = 11.11 s = 'abcde' b = True l = ['春','夏',123,'ABC'] t = (111,222,333,444) d = {'username':'xilou','age':18,'info':'hahaha'} return render(request,'index.html',locals())
html中用模板语言接受这些变量
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <p>{{ n }}</p> <p>{{ f }}</p> <p>{{ s }}</p> <p>{{ b }}</p> <p>{{ l }}</p> <p>{{ d }}</p> <p>{{ t }}</p> </body> </html>
发现这些数据全部都会被接收,也就是模板语言支持python中所有的变量的数据类型
既然能接收变量,那能不能接收函数和类呢
def func(): print('执行了') return 'a' class MyClass(object): def get_self(self): return 'self' @staticmethod def get_func(): return 'func' @classmethod def get_class(cls): return 'cls' def __str__(self): return '到底会不会?'
html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body>
<p>{{ func }}</p>
<p>{{ MyClass }}</p>
<p>{{ obj }}</p>
<p>{{ obj.get_self }}</p>
<p>{{ obj.get_func }}</p>
<p>{{ obj.get_class }}</p>
</body> </html>
对于函数:传递函数名会自动加括号调用 但是模版语法不支持给函数传额外的参数
对于类:传类名的时候也会自动加括号调用(实例化)
内部能够自动判断出当前的变量名是否可以加括号调用 如果可以就会自动执行 针对的是函数名和类名
django模版语法的取值 是固定的格式 只能采用“句点符”
<p>{{ d.username }}</p> <p>{{ l.0 }}</p> <p>{{ d.hobby.3.info }}</p>
二、过滤器
过滤器类似于python的内置函数,用来把视图传入的变量值加以修饰后再显示,具体语法如下
{{ 变量名|过滤器名:传给过滤器的参数 }}
常用的过滤器
#1、default #作用:如果一个变量值是False或者为空,使用default后指定的默认值,否则,使用变量本身的值,如果value=’‘则输出“nothing” {{ value|default:"nothing" }} #2、length #作用:返回值的长度。它对字符串、列表、字典等容器类型都起作用,如果value是 ['a', 'b', 'c', 'd'],那么输出是4 {{ value|length }} #3、filesizeformat #作用:将值的格式化为一个"人类可读的"文件尺寸(如13KB、4.1 MB、102bytes等等),如果 value 是 12312312321,输出将会是 11.5 G {{ value|filesizeformat }} #4、date #作用:将日期按照指定的格式输出,如果value=datetime.datetime.now(),按照格式Y-m-d则输出2019-02-02 {{ value|date:"Y-m-d" }} #5、slice #作用:对输出的字符串进行切片操作,顾头不顾尾,如果value=“egon“,则输出"eg" {{ value|slice:"0:2" }} #6、truncatechars #作用:如果字符串字符多于指定的字符数量,那么会被截断。截断的字符串将以可翻译的省略号序列(“...”)结尾,如果value=”hello world {{ value|truncatechars:8 }} #7、truncatewords #作用:同truncatechars,但truncatewords是按照单词截断,注意末尾的3个点不算作单词,如果value=”hello world egon 嘎嘎“,则输 {{ value|truncatewords:2 }} #8、safe #作用:出于安全考虑,Django的模板会对HTML标签、JS等语法标签进行自动转义,例如value="<script>alert(123)</script>",模板变量 {{ value|safe }}
<h1>过滤器</h1> <p>统计长度:{{ s|length }}</p> <p>默认值(第一个参数布尔值是True就展示第一个参数的值否在展示冒号后面的值):{{ b|default:'啥也不是' }}</p> <p>文件大小:{{ file_size|filesizeformat }}</p> <p>日期格式化:{{ current_time|date:'Y-m-d H:i:s' }}</p> <p>切片操作(支持步长):{{ l|slice:'0:4:2' }}</p> <p>切取字符(包含三个点):{{ info|truncatechars:9 }}</p> <p>切取单词(不包含三个点 按照空格切):{{ egl|truncatewords:9 }}</p> <p>切取单词(不包含三个点 按照空格切):{{ info|truncatewords:9 }}</p> <p>移除特定的字符:{{ msg|cut:' ' }}</p> <p>拼接操作:{{ l|join:'$' }}</p> <p>拼接操作(加法):{{ n|add:10 }}</p> <p>拼接操作(加法):{{ s|add:msg }}</p> <p>转义:{{ hhh|safe }}</p> <p>转义:{{ sss|safe }}</p> <p>转义:{{ res }}</p>
三、标签
标签是为了在模板中完成一些特殊功能,语法为{%
标签名
%},一些标签还需要搭配结束标签
{%
endtag
%}
1.for标签
#1、遍历每一个元素: {% for person in person_list %} <p>{{ person.name }}</p> {% endfor %} #2、可以利用{% for obj in list reversed %}反向循环。 #3、遍历一个字典: {% for key,val in dic.items %} <p>{{ key }}:{{ val }}</p> {% endfor %} #4、循环序号可以通过{{ forloop }}显示 forloop.counter 当前循环的索引值(从1开始) forloop.counter0 当前循环的索引值(从0开始) forloop.revcounter 当前循环的倒序索引值(从1开始) forloop.revcounter0 当前循环的倒序索引值(从0开始) forloop.first 当前循环是第一次循环则返回True,否则返回False forloop.last 当前循环是最后一次循环则返回True,否则返回False forloop.parentloop 本层循环的外层循环 #5、for标签可以带有一个可选的{% empty %} 从句,在变量person_list为空或者没有被找到时,则执行empty子句 {% for person in person_list %} <p>{{ person.name }}</p> {% endfor %}
2.if标签
# 1、注意: {% if 条件 %}条件为真时if的子句才会生效,条件也可以是一个变量,if会对变量进行求值,在变量值为空、或者视图没有为其传值的情况下均为 # 2、具体语法 {% if num > 100 or num < 0 %} <p>无效</p> {% elif num > 80 and num < 100 %} <p>优秀</p> {% else %} <p>凑活吧</p> {% endif %} #3、if语句支持 and 、or、==、>、<、!=、<=、>=、in、not in、is、is not判断
if与for混用例子
{% for foo in lll %} {% if forloop.first %} <p>这是我的第一次</p> {% elif forloop.last %} <p>这是最后一次啊</p> {% else %} <p>{{ foo }}</p> {% endif %} {% empty %} <p>for循环的可迭代对象内部没有元素 根本没法循环</p> {% endfor %}
3.with标签
with标签用来为一个复杂的变量名起别名,如果变量的值来自于数据库,在起别名后只需要使用别名即可,无需每次都向数据库发送请求来重新获取
{% with li.1.upper as v %}
{{ v }}
{% endwith %}
四、自定义过滤器和标签以及inclusion_tag
创建自定义过滤器的三步
1.在应用下创建一个名字”必须“叫templatetags文件夹 2.在该文件夹内创建“任意”名称的py文件 eg:mytag.py 3.在该py文件内"必须"先书写下面两句话(单词一个都不能错) from django import template register = template.Library()
自定义过滤器
@register.filter(name='baby') def my_sum(v1, v2): return v1 + v2
使用
{% load mytag %}
<p>{{ n|baby:666 }}</p>
自定义标签(类似于自定义函数)
@register.simple_tag(name='plus') def index(a,b,c,d): return '%s-%s-%s-%s'%(a,b,c,d)
使用
标签多个参数彼此之间空格隔开 <p>{% plus 'jason' 123 123 123 %}</p>
自定义inclusion_tag
内部原理
先定义一个方法
在页面上调用该方法 并且可以传值
该方法会生成一些数据然后传递给一个html页面
之后将渲染好的结果放到调用的位置
@register.inclusion_tag('left_menu.html') def left(n): data = ['第{}项'.format(i) for i in range(n)] # 第一种 # return {'data':data} # 将data传递给left_menu.html # 第二种 return locals() # 将data传递给left_menu.html {% left 5 %}
五、模板继承与导入
有使用网页很多都一样的,只是改了一些部分,这些重复的部分,我们虽然可以直接拷贝代码,但是会显得很冗余,
所以我们就要通过模板的继承与导入来减少这部分的代码冗余
我们只要把相同的部分用
{% block content %}
模版内容
{% endblock %}
包起来,然后再通过
{% extends ‘xx.html' %}
继承就可以继承那些重复的部分了
一般情况下模版页面上应该至少有三块可以被修改的区域
1.css区域
2.html区域
3.js区域
{% block css %}
{% endblock %}
{% block content %}
{% endblock %}
{% block js %}
{% endblock %}
# 每一个子页面就都可以有自己独有的css代码 html代码 js代码
模板的导入我们只需要通过
{% include 'xxx.html' %}
即可