模板的介绍
网站如何向客户端发送一个漂亮的页面呢
-
html
、css
、js
-
但是如果将这些字段都写到视图中,作为
HttpResponse()
的参数响应给客户端,将会有以下问题 -
视图部分代码臃肿, 耦合度高
-
这样定义的字符串是不会出任何效果和错误的
-
效果无法及时查看.有错也不容易及时发现
解决问题
模板 Template
-
MVT设计模式中的T,Template
-
M全拼为
Model
,与MVC中的M功能相同,负责和数据库交互,进行数据处理。 -
V全拼为
View
,与MVC中的C功能相同,接收请求,进行业务处理,返回应答。 -
T全拼为
Template
,与MVC中的V功能相同,负责封装构造要返回的html。
from flask import Flask
app = Flask(__name__)
@app.route("/")
def index():
return "<h3>Hell</h3><p>Flask</p>"
if __name__ == "__main__":
app.run(debug=True)
模板的使用
在 Flask中,配套的模板是 Jinja2
,Jinja2的作者也是Flask的作者。这个模板非常的强大,并且执行效率高。
使用步骤
- 创建模板
- 在应用同级目录下创建模板文件夹
templates
文件夹名称固定写法 - 在templates文件夹下, 创建应用同名文件夹. 例, Book
- 在应用同名文件夹下创建网页模板文件. 例 :index.html
- 设置模板查找路径
- 模板处理数据
使用render_template()
使用模板
from flask import Flask,render_template
app = Flask(__name__)
@app.route("/")
def index():
return render_template("01_index.html")
if __name__ == "__main__":
app.run(debug=True)
<!DOCTYPE html>
<html lang="en">
<head>
<style>
h1 {
background-color: red;
}
p {
background-color: blue;
}
</style>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>模板的使用</title>
</head>
<body>
<h1>Hello模板的使用</h1>
<p>这个是模板的使用案例</p>
</body>
</html>
模板传递参数
在使用render_template渲染模版的时候,可以传递关键字参数
from flask import Flask,request,render_template
from werkzeug.routing import BaseConverter
app = Flask(__name__)
@app.route("/")
def index1():
return render_template("02_index.html",info="Flask模板传参")
@app.route("/index2")
def index2():
return render_template("02_index.html",info="python中的Flask模板传参",args="换了一个变量名")
@app.route("/home")
def home():
context = {
"uname":"吕布",
"age":18,
"height":180,
"arms":{"melee":"方天画戟","range":"弓箭","transport":"赤兔马"}
}
return render_template("02_index.html",**context)
if __name__ == "__main__":
app.run(debug=True)
<!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.0">
<title>模板传参</title>
</head>
<body>
<h1>模板传参</h1>
<p>这个是关于{{info}}的内容</p><hr>
<p>这是换了一个效果:{{args}}</p><hr>
<p>{{uname}}的年龄是{{age}}岁,身高是{{height}},他的近战武器是{{arms["melee"]}},远程武器是{{arms.get("range")}},他的坐骑是{{arms.transport}}</p>
</body>
</html>
模板中使用url_for
解析出该函数映射的路由地址
from flask import Flask,render_template
app = Flask(__name__)
@app.route("/")
def index1():
return render_template("03_index.html")
@app.route("/home/")
def index2():
return render_template("03_index.html")
if __name__ == "__main__":
app.run(debug=True)
<!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.0">
<title>url_for的使用</title>
</head>
<body>
<h1>url_for的使用</h1><hr>
<p>index1的路由是{{url_for("index1")}}</p><hr>
<p>index2的路由是{{url_for("index2")}}</p>
</body>
</html>
过滤器
有时候我们想要在模版中对一些变量进行处理,那么就必须需要类似于Python中的函数一样,可以将这个值传到函数中,然后做一些操作。
在模版中,过滤器相当于是一个函数,把当前的变量传入到过滤器中,然后过滤器根据自己的功能,再返回相应的值,之后再将结果渲染到页面中
过滤器名 | 解释 | 举例 |
---|---|---|
abs(value) | 返回一个数值的绝对值 | -1 | abs |
int(value) | 将值转换为int类型 | |
float(value) | 将值转换为float类型 | |
string(value) | 将变量转换成字符串 | |
default(value,default_value,boolean=false) | 如果当前变量没有值,则会使用参数中的值来代替。如果想使用python的形式判断是否为false,则可以传递boolean=true。也可以使用or来替换 | name|default(‘xiaotuo’) |
safe(value) | 如果开启了全局转义,那么safe过滤器会将变量关掉转义 | content_html|safe |
escape(value)或e | 转义字符,会将<、>等符号转义成HTML中的符号 | content|escape |
first(value) | 返回一个序列的第一个元素 | |
format(value,*arags,**kwargs) | 格式化字符串 | |
last(value) | 返回一个序列的最后一个元素。 |
自定义过滤器
只有当系统提供的过滤器不符合需求后,才须自定义过滤器。
过滤器本质上就是一个函数。
如果在模版中调用这个过滤器,那么就会将这个变量的值作为第一个参数传给过滤器这个函数,
然后函数的返回值会作为这个过滤器的返回值。
需要使用到一个装饰器:@app.template_filter('过滤器名称')
from flask import Flask,render_template
app = Flask(__name__)
@app.template_filter("cut") # 自定义过滤器的名称
def cut(value):
value = value.replace("你","我")
return value
@app.route("/")
def index():
info = "你好啊"
return render_template("07_index.html",info = info)
if __name__ == "__main__":
app.run(debug=True)
<!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.0">
<title>自定义过滤器</title>
</head>
<body>
<h1>自定义过滤器</h1>
过滤前的数据{{ info }}<br>
过滤后的数据{{ info | cut }}<br>
</body>
</html>
自定义时间过滤器
操作发布新闻 与现在的时间间隔 **
from datetime import datetime
from flask import Flask,render_template
app = Flask(__name__)
"""实现类似朋友圈多少时间之前发布的信息"""
# 假设数据库中的数据是2020/01/01 03:10:10
# 现在的时间是2022/10/31 08:10:10
@app.template_filter("handler_time")
def handler_time(time):
# 获取当前时间
now = datetime.now()
# 相差时间由秒为单位
# total_seconds() 此方法的返回类型是一个数字,该数字是该时间段内覆盖的总秒数
temp_stamp = (now - time).total_seconds()
if temp_stamp < 60:
return "1分钟之前"
elif 60*60 > temp_stamp >= 60:
return "1小时之前"
elif 24*60*60>temp_stamp>=60*60:
hours = temp_stamp/(60*60)
return f"{int(hours)}小时之前"
elif 24*60*60*30>=temp_stamp>=24*60*60:
day = temp_stamp/(60*60*24)
return f"{int(day)}天以前"
else:
return "很久以前"
@app.route("/")
def index():
tmp_time = datetime(2022,10,31,10,10,19)
return render_template("08_index.html",tmp_time = tmp_time)
if __name__ == "__main__":
app.run(debug=True)
<!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.0">
<title>自定义时间过滤器的使用</title>
</head>
<body>
<h1>自定义时间过滤器的使用</h1>
数据过滤后:{{ tmp_time|handler_time}}
</body>
</html>
流程控制-选择结构
所有的控制语句都是放在{% ... %}
中,并且有一个语句{% endxxx %}
来进行结束
if
:if语句和python中的类似,可以使用>,<,<=,>=,==,!=
来进行判断,也可以通过and,or,not,()
来进行逻辑合并操作
from flask import Flask,render_template
app = Flask(__name__)
@app.route("/")
def index():
uname = "李四"
return render_template("09_index.html",uname = uname)
if __name__ == "__main__":
app.run(debug=True)
<!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.0">
<title>流程控制——选择结构</title>
</head>
<body>
<h1>流程控制——选择结构</h1>
{% if uname == "张三"%}
我是{{ uname }}
{% else %}
我不是张三,而是{{ uname }}
{% endif %}
</body>
</html>
练习
模拟登录页面
from flask import Flask,render_template,request
app = Flask(__name__)
@app.route("/")
def index():
return render_template("10_index2.html")
@app.route("/login")
def login():
user = request.args.get("user")
return render_template("10_index2.html",user=user)
if __name__ == "__main__":
app.run(debug=True)
<!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.0">
<title>选择结构</title>
</head>
<body>
{% if not user %}
<a href="/login?user='nick'">请登录</a>
<span>免费注册</span>
{% else %}
<h1>欢迎 {{ user }} </h1>
<h2>首页</h2>
{% endif %}
</body>
</html>
流程控制-循环结构
实现九九乘法表
from flask import Flask,render_template
app = Flask(__name__)
@app.route("/")
def index():
return render_template("11_index.html")
if __name__ == "__main__":
app.run(debug=True)
<!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.0">
<title>九九乘法表</title>
</head>
<body>
<table border="1">
{% for i in range(1,10) %}
<tr>
{% for j in range(1,i+1) %}
<td>{{j}}*{{i}} = {{i*j}}</td>
{% endfor %}
</tr>
{% endfor %}
</table>
</body>
</html>
宏的使用
模板中的宏跟python中的函数类似,可以传递参数,但是不能有返回值。
可以将一些经常用到的代码片段放到宏中,然后把一些不固定的值抽取出来当成一个变量。
定义宏
{% macro inp(type="text",name="",value="")%}
<input type="{{type}}" name={{name}} value="{{value}}">
{% endmacro %}
使用宏
<!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.0">
<title>宏的使用</title>
</head>
{% import 'macros/common.html' as mc %}
{% from "macros/common.html" import inp with context %}
<body>
<h1>未使用宏</h1>
<tr>
<td>用户名:</td>
<td><input type="text" value="{{nick}}"></input></td><br>
</tr>
<tr>
<td>密码:</td>
<td><input type="password" name="" id=""></td><br>
</tr>
<tr>
<td>登录:</td>
<td><input type="submit" value="登录" name="" id=""></td>
</tr>
</body><hr>
<body>
<h1>宏的使用</h1>
<tr>
<td>用户名:</td>
<td>{{inp(name="uname")}}</td><br>
</tr>
<tr>
<td>密码:</td>
<td>{{inp("password","pwd")}}</td><br>
</tr>
<tr>
<td>登录:</td>
<td>{{inp("submit",value="登录")}}</td>
</tr>
</body>
</html>
```language
include导入模板
页面的复用
-
这个标签相当于是直接将指定的模版中的代码复制粘贴到当前位置。
-
include标签,如果想要使用父模版中的变量,直接用就可以了,不需要使用
with context
。 -
include的路径,也是跟import一样,直接从
templates
根目录下去找,不要以相对路径去找。