jinja2模板
视图函数的主要作用是,处理业务逻辑,返回响应内容
flask是使用jinja2这个模板引擎来渲染模板
使用模板的好处
- 视图函数只负责业务逻辑和数据处理
- 模板取到视图函数的数据结果进行展示
- 代码结构清晰,耦合度低
1、jinja2模板介绍
模板传参
- 再使用render_template渲染模板的时候,可以传递关键字参数,以后直接在模板中使用即可
- 如果参数过多,可以将所有的参数放到一个字典或列表中。将字典打散成关键字参数可以在参数前面加**
from flask import Flask,render_template
app = Flask(__name__)
student = {
'name': 'zhangsan',
'age':8,
'gender':'男'
}
student_list = [
{'name': 'zhangsan','age':18,'gender':'男'},
{'name': 'lisi','age':68,'gender':'女'},
{'name': 'wangwu','age':16,'gender':'男'}
]
student_dict = {
'a':{'name': 'zhangsan','age':18,'gender':'男'},
'b':{'name': 'lisi','age':28,'gender':'女'},
'c':{'name': 'wangwu','age':19,'gender':'男'}
}
@app.route('/test1')
def test1():
return render_template('01.html', **student) # 为了方便在模板中使用,可以把字典打散
@app.route('/test2')
def test2():
return render_template('02.html', stu_list = student_list)
@app.route('/test3')
def test3():
return render_template('03.html', stu_dict = student_dict)
if __name__ == '__main__':
app.run()
01.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>第一个模板</title>
</head>
<body>
学生姓名:{{ name }}
学生年龄:{% if age >= 18 %}
已经成年
{% else %}
未成年
{% endif %}
学生性别:{{ gender }}
</body>
</html>
结果
02.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>第二个模板</title>
</head>
<body>
{{ stu_list }}
<table border="1px">
<tr>
<td>序号</td>
<td>姓名</td>
<td>年龄</td>
<td>性别</td>
</tr>
{% for stu in stu_list %}
<tr>
<td>{{ loop.index }}</td>
<td>{{ stu.name }}</td> <!-- 由于stu是字典,有三种写法得到key的value-->
{% if stu.age >= 60 %}
<td>已退休</td>
{% elif stu.age >= 18 %}
<td>已成年</td>
{% else %}
<td>未成年</td>
{% endif %}
{# <td>{{ stu.get('age') }}</td>#}
<td>{{ stu['gender'] }}</td>
</tr>
{% endfor %}
</table>
</body>
</html>
结果
03.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>第三个模板</title>
</head>
<body>
{{ stu_dict }}
<table border="1px">
<tr>
<td>序号</td>
<td>姓名</td>
<td>年龄</td>
<td>性别</td>
</tr>
{% for stu_key,stu in stu_dict.items() %}
<tr>
<td>{{ loop.index }},key:{{ stu_key }}</td>
<td>{{ stu.name }}</td> <!-- 由于stu是字典,有三种写法得到key的value-->
{% if stu.age >= 60 %}
<td>已退休</td>
{% elif stu.age >= 18 %}
<td>已成年</td>
{% else %}
<td>未成年</td>
{% endif %}
{# <td>{{ stu.get('age') }}</td>#}
<td>{{ stu['gender'] }}</td>
</tr>
{% endfor %}
</table>
</body>
</html>
结果
语法
- 控制结构(逻辑代码){%%}
- 变量取值{{}}
- 注释{##}
2、表达式
- 最常用的是变量,由Flask渲染模板时传过来,比如name
- 也可以是任意一种Python基础类型,比如字符串{{stu}};或者数值,列表,元祖,字典,布尔值。
- 运算。包括算数运算,如{{ 2 + 3 }};比较运算,如{{ 2 > 1 }};逻辑运算,如{{ False and True }}
- 过滤器|和测试器is
- 函数调用,如{{ current_time() }};
- 数组下标操作,如{{ arr[1] }}
- in操作符,如{{ 1 in [1,2,3] }}
- 字符串连接符~,作用同Python中的 “+” 一样,如{{ "Hello " ~ name ~ “!” }}
- None值处理{{name or “”}
3、过滤器
过滤器实质上是一个转换函数。变量可以通过过滤器进行修改,过滤器可以理解为是jinja2里面的内置函数和字符串处理函数
常用的过滤器
过滤器名称 | 描述 |
---|---|
safe | 渲染时值不转义 |
capitalize | 把值的首字母转换成大写,其他字母转换成小写 |
lower | 把值转换成小写形式 |
upper | 把值转换成大写形式 |
title | 把值中每个单词的首字母都转换成大写 |
trim | 把值的首尾空格去掉 |
striptags | 渲染之前把值中所有的HTML标签都删掉 |
join | 拼接多个值为字符串 |
replace | 替换字符串的值 |
round | 默认对数字进行四舍五入,也可以用参数进行控制 |
int | 把值转换成整型 |
过滤器.py
from flask import Flask,render_template
app = Flask(__name__)
student = {
'name': 'zhangsan',
'age':8,
'gender':'男'
}
@app.route('/str')
def test1():
return render_template('04字符串的过滤器.html')
@app.route('/number')
def test2():
return render_template('05数字的过滤器.html')
@app.route('/list')
def test3():
return render_template('06列表的过滤器.html')
@app.route('/dict')
def test4():
return render_template('07字典的过滤器.html')
@app.template_filter('get_top3')
def get_top3(lst):# 取列表的前3个元素
return lst[:3]
def get_qu(lst):# 计算列表中每个元素的平方,
return list(map(lambda x:x**2,lst))
app.jinja_env.filters['get_qu'] = get_qu
@app.route('/my_filter')
def test5():
return render_template('08自定义的过滤器.html')
if __name__ == '__main__':
app.run()
字符串过滤器
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>字符串的过滤器</title>
</head>
<body>
{# 当变量数据没有传入,可以给变量设置默认值 #}
<p>{{ name | default('这个人很懒,什么都没有留下!!!') }}</p><br>
{# 字符串的大小写转换 #}
<p>{{ 'XYZ' | lower }}</p><br>
{# 反转 #}
<p>{{ 'hello world' | reverse }}</p><br>
{# 格式化 #}
<p>{{ '今天是%d号,天气%s' | format(17,'下雨')}}</p><br>
{# 关闭html的自动转义 #}
<p>{{ '<em>name</em>' | safe }}</p>
</body>
</html>
结果
数字过滤器
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>数字的过滤器</title>
</head>
<body>
{# 四舍五入的转换,默认取整数部分 #}
<p>{{ 3.1415926 | round }}</p><br>
{# 小数点后面截取n位 #}
<p>{{ 3.1415 | round(3) }}</p><br>
{# 取绝对值 #}
<p>{{ -100 | abs }}</p><br>
{# #}
{# <p>{{ }}</p><br>#}
{# <p>{{ }}</p><br>#}
{# <p>{{ }}</p><br>#}
</body>
</html>
结果
列表的过滤器
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>列表的过滤器</title>
</head>
<body>
{# 定义一个nums变量 #}
{% set nums = [1,5,2,6,8,3] %}
{# 取第一个值 #}
<p>{{ nums | first }}</p><br>
{# 列表长度 #}
<p>{{ nums | length }}</p><br>
{# 求和 #}
<p>{{ nums | sum }}</p><br>
{# 排序 #}
<p>{{ nums | sort }}</p><br>
{# 变成字符串 #}
<p>{{ nums | join(' - ') }}</p><br>
{# <p>{{ }}</p><br>#}
</body>
</html>
结果
字典过滤器
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>字典的过滤器</title>
</head>
<body>
{# 定义一个字典 #}
{% set students = [
{'name':'zs','age':38,'gender':'女'},
{'name':'ls','age':68,'gender':'男'},
{'name':'ww','age':8,'gender':'女'}
] %}
{# 根据指定字段排序 #}
<ul>
{% for stu in students | sort(attribute='age',reverse=False) %}
<li>{{ stu.name }},{{ stu.age }}</li>
{% endfor %}
</ul>
{# 上面的数据分组,每组变成一个子列表 #}
<ul>
{% for group in students |groupby('gender') %}
<li>{{ group.grouper }}</li>
{% for stu in group.list %}
<li>{{ stu.name }},{{ stu.gender }}</li>
{% endfor %}
{% endfor %}
</ul>
{# 取出字典中的某一列,组成一个大的列表,然后再把列表变成字符串 #}
<p>{{ students | map(attribute='name') | join('-') }}</p><br>
{# <p>{{ }}</p><br>#}
</body>
</html>
结果
自定义的过滤器
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>自定义的过滤器</title>
</head>
<body>
<p>{{ [1,2,3,4,5,6,7] | get_top3 }}</p><br>
<p>{{ [1,2,3,4,5,6] | get_qu }}</p>
</body>
</html>
结果
4、测试器
测试器总是返回一个布尔值,它可以用来测试一个变量或者表达式,使用"is"关键字来测试
测试器本质上也是一个函数,它的第一个参数就是待测试的变量,在模板中可以省略,如果有第二个参数,模板中就必须传进去。测试器函数返回的必须是一个布尔值,这样才可以用来给if语句做判断
测试器官网文档
测试器.py
from flask import Flask,render_template
import re
app = Flask(__name__)
@app.route('/test_demo1')
def test1():
return render_template('09测试器.html')
# 自定义测试器,创建函数,注册
@app.template_test('isphone')
def test_phone(phone): # 测试手机号是否合法
phone_re = r'1[3-9]\d{9}'
return re.match(phone_re,phone)
def start_with(s,suffix):
return s.lower().startswith(suffix.lower())
app.jinja_env.tests['startwith'] = start_with
if __name__ == '__main__':
app.run()
测试器.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>测试器</title>
</head>
<body>
{# 检查变量是否被定义,也可以用undefined检查是否未被定义 #}
{% if name is defined %}
<p>Name is: {{ name }}</p>
{% endif %}
{% if name is undefined %}
<p>Name 没有定义</p>
{% endif %}
{# 检查是否所有字符都是大写 #}
{% if name is upper %}
<h2>"{{ name }}" are all upper case.</h2>
{% endif %}
{# 检查变量是否为空 #}
{% if name is none %}
<h2>Variable is none.</h2>
{% endif %}
{# 检查变量是否为字符串,也可以用number检查是否为数值 #}
{% if name is string %}
<h2>{{ name }} is a string.</h2>
{% endif %}
{# 检查数值是否是偶数,也可以用odd检查是否为奇数 #}
{% if 2 is even %}
<h2>Variable is an even number.</h2>
{% endif %}
{# 检查变量是否可被迭代循环,也可以用sequence检查是否是序列 #}
{% if [1,2,3] is iterable %}
<h2>Variable is iterable.</h2>
{% endif %}
{# 检查变量是否是字典 #}
{% if {'name':'test'} is mapping %}
<h2>Variable is dict.</h2>
{% endif %}
<hr>
{% if '10011110000' is isphone %}
<p>是手机号</p><br>
{% else %}
<p>不是手机号</p><br>
{% endif %}
{% if 'hello' is startwith('he') %}
<p>是以he开头</p>
{% endif %}
</body>
</html>
结果
5、模板的继承
继承.py
from flask import Flask,render_template
app = Flask(__name__)
@app.route('/extend')
def hello_world():
return render_template('010child.html')
@app.route('/include')
def to_include():
return render_template('010include.html')
if __name__ == '__main__':
app.run()
parent.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>父模板</title>
</head>
<body>
{% block temp1 %}
<p>页面的头部</p>
<hr>
{% endblock %}
{% block temp2 %}
<hr>
<p>页面的尾部</p>
{% endblock %}
</body>
</html>
child.html
{% extends '010parent.html' %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>子模板</title>
</head>
<body>
{% block temp1 %}
{{ super() }}
<p>子模板的内容</p>
{% endblock %}
</body>
</html>
结果
include.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>include</title>
</head>
<body>
{% include 'header.html' %}
<p>页面中间的内容</p>
{% include 'footer.html' %}
</body>
</html>
header.html
<p>页面的头部</p>
<hr>
footer
<hr>
<p>页面的尾部</p>
结果
6、模板中使用URL_FOR函数
模版中的 url_for 跟我们后台视图函数中的 url_for 使用起来基本是一模一样的。也是传递视图函数的名字,也
可以传递参数。使用的时候,需要在 url_for 左右两边加上一个 {{ url_for(‘func’) }}
url_for函数.py
from flask import Flask,render_template
app = Flask(__name__)
@app.route('/')
def hello_world():
return render_template('index.html')
@app.route('/login/<un>')
def user_login(un):
print(un)
return f'ok,用户名{un}'
if __name__ == '__main__':
app.run()
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<a href="{{ url_for('user_login',un='zs',id=2) }}">登录</a>
<img src="{{ url_for('static',filename='7.jpg') }}">
</body>
</html>
进入页面
点击登录
下面的图片为加载的静态资源