Flask 学习笔记
一、模板介绍
模板是一个 web 开发必备的模块。因为我们在渲染一个网页的时候,并不是只渲染一个纯文本字符串,而是需要渲染一个有富文本标签的页面。这时候我们就需要使用模板了。在 Flask 中, 配套的模板是 Jinja2
,Jinja2 的作者也是 Flask 的作者。这个模板非常的强大,并且执行效率高。
1.1、Flask 渲染 Jinja 模板
在 flask 中可以直接以字符串的形式返回实现前端代码的效果,但这么做显然不太可能在工作中使用。
from flask import Flask
app = Flask(__name__)
@app.route("/")
def index():
return '<input type="text" class="s_ipt" name="wd" id="kw" maxlength="100" autocomplete="off">'
if __name__ == '__main__':
app.run(debug=True)
渲染模块,说白了就是在 py
文件导入前端代码文件 html
进行使用,同时 py
文件也可以向 html
文件传递数据。通过 render_template()
方法即可实现。
值得注意的是,Flask()
方法设置 render_template() 默认访问的是当前文件夹下的 templates 文件夹(创建 flask 项目会自动创建),所有的前端文件都应放在这。当然也可以通过 template_folder
参数修改(但比建议修改)。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<input type="text" class="s_ipt" name="wd" id="kw" maxlength="100" autocomplete="off">
</body>
</html>
from flask import Flask, render_template
# 绝对路径 相对路径都可以
app = Flask(__name__, template_folder=r"./demo")
@app.route("/")
def index():
return render_template("index.html")
if __name__ == '__main__':
app.run(debug=True)
1.2、传参数
- 直接传
@app.route("/")
def index():
# 直接传
return render_template("index.html", name="直接传", age=18)
<!-- 在html文件使用 {{}} 接收 -->
<h2>{{name}}</h2>
<h2>{{age}}</h2>
- 使用字典传
@app.route("/")
def index():
dic = {
"name": "用户名",
"password": "密码"
}
return render_template("index.html", context=dic)
<h2>{{context}}</h2>
<h2>{{context.name}}</h2>
- 使用 ** 字典
@app.route("/")
def index():
# 使用 ** 可以把 "name": "用户名" 转为 "name"="用户名"
dic = {
"name": "用户名",
"password": "密码",
"books": {
"Python": 56,
"Java": 55
},
"lis": [1, 2, 3]
}
return render_template("index.html", **dic)
<h2>{{name}}</h2>
<h2>{{password}}</h2>
<!-- 可用 "." , 也可用 "索引" 访问 -->
<h2>{{books.Python}}</h2>
<h2>{{books["Java"]}}</h2>
<h2>{{lis.1}}</h2>
<h2>{{lis[0]}}</h2>
- 再说过小 bug 吧
在 flask 引用的 html 文件中进行代码注释不能用<!-- -->
,因为它仍会对其中的变量等进行索引,若变量不存在代码有错误它还是会报错。因此可以用{# #}
,当然那些用于解释代码的注释是没什么影响的。
<!-- 在用 ** 引入的例子中,在 html 文件加入下面的注释代码仍会报错 -->
<!-- <h2>{{context}}</h2> #} -->
<!-- 改为下列就不会-->
{# <h2>{{context}}</h2> #}
二、Jinja2 模板过滤器
过滤器是通过管道符号 |
在前端代码进行使用的,例如:{{ name|length }}
,将返回变量 name 的长度。过滤器相当于是一个函数,把当前的变量传入到过滤器中,然后过滤器根据自己的功能,再返回相应的值,之后再将结果渲染到页面中。Jinja2 中内置了许多过滤器,在这里可以看到所有的过滤器。
2.1、内置的过滤器
-
abs(value)
:返回一个数值的绝对值。 -
length(value)
:返回一个序列或者字典的长度。 -
default(value, default_value, boolean=false)
:如果当前变量没有值,则会使用参数中的值来代替。如果当前变量不存在(未创建),则会使用 default_value 来替代。boolean=False 默认是在只有这个变量未定义的时候才会使用 default 中的值,如果想使用 python 的形式判断是否为 false,则可以传递 boolean=true。
@app.route("/")
def index():
dic = {
"name": " 老王 ",
"num": -66,
"val": None
}
return render_template("index.html", **dic)
<body>
<p>{{ name }}</p>
<p>{{ name|length }}</p>
<p>{{ num|abs }}</p>
<p>{{ val|default("默认值") }}</p>
<p>{{ acd|default("acd 变量不存在") }}</p>
<p>{{ val|default("Python 的形式判断是否为 false", boolean=true) }}</p>
</body>
-
escape(value)或e
:转义字符,会将<、>等符号转义成 HTML 中的符号(在页面源代码中进行了转义)。 -
safe(value)
:如果开启了全局转义,那么 safe 过滤器会将变量关掉转义。 -
first(value)
:返回一个序列的第一个元素。 -
last(value)
:返回一个序列的最后一个元素。 -
join(value, d=u'')
:将一个序列用d
这个参数的值拼接成字符串。 -
format(value, *arags, **kwargs)
:格式化字符串。
@app.route("/")
def index():
dic = {
"name": " 老王 ",
"num": -66,
"val": None,
"h1": "<h1>你好 li</h1>",
"books": ['Python', 'Java', 'PHP']
}
return render_template("index.html", **dic)
<p>{{ h1|escape }}</p>
<!-- 似乎不用 escape 也可以自动转换 -->
<p>{{ h1 }}</p>
<!-- 关闭自动转义 -->
{% autoescape off %}
<p>{{ h1 }}</p>
{% endautoescape %}
<!-- 也可以使用 safe 使其变为安全变量, 达到关闭自动转义的效果 -->
<p>{{ h1|safe }}</p>
<p>{{ books|first }}</p>
<p>{{ books|last }}</p>
<p>{{ books|length }}</p>
<!-- 若是合乎逻辑的话, 也可以联用 -->
<p>{{ books|first|length }}</p>
<p>{{ books|first|last }}</p>
<p>{{ books|join(d='-') }}</p>
<p>{{ "%s - %s"|format(h1, name) }}</p>
-
int(value)
:将值转换为 int 类型。 -
float(value)
:将值转换为 float 类型。 -
string(value)
:将变量转换成字符串。 -
lower(value)
:将字符串转换为小写。 -
upper(value)
:将字符串转换为大写。 -
replace(value, old, new)
: 替换将 old 替换为 new 的字符串。 -
truncate(value, length=255, killwords=False)
:截取 length 长度的字符串。常用于文章标题的显示,太长在网页中不能完全显示,所以后面的内容用...
代替,因此 length 的值不能小于 3,显示的文字 = length - 3
。 -
striptags(value)
:删除字符串中所有的 HTML 标签,如果出现多个空格,将替换成一个空格。 -
trim(value)
:截取字符串前面和后面的空白字符。 -
wordcount(value)
:计算一个长字符串中单词的个数(以空格为分隔,并不是严格的按单词分)。
@app.route("/")
def index():
dic = {
"name": " 老王 ",
"num": -66,
"val": None,
"h1": "<h1>你好 li</h1>",
"books": ['Python', 'Java', 'PHP'],
"user": "Cool",
"wc": "hello llo i"
}
return render_template("index.html", **dic)
<p>{{ num|int }}</p>
<p>{{ num|float }}</p>
<p>{{ num|string }}</p>
<p>{{ user|lower }}</p>
<p>{{ user|upper }}</p>
<p>{{ user|replace("o", "88") }}</p>
<p>{{ wc|truncate(length=4) }}</p>
<p>{{ h1|striptags }}</p>
<p>截取前的长度:{{ name|length }}</p>
<p>截取后的长度:{{ name|trim|length }}</p>
<p>{{ wc|wordcount }}</p>
2.2、自定义过滤器
- 定义一个简单的过滤器
@app.template_filter("my_cut")
def cut(value):
'''
把 hello 替换成 你好
:param value:
:return:
'''
return value.replace("hello", "你好")
<p>{{ wc|my_cut }}</p>
- 定义一个显示时间的过滤器
@app.route("/")
def index():
dic = {
# datetime(年, 月, 日, 时, 分, 秒)
"now_time1": datetime(2020, 4, 16, 14, 15, 0),
"now_time2": datetime(2020, 4, 16, 14, 0, 0),
"now_time3": datetime(2020, 4, 16, 10, 0, 0)
}
return render_template("index.html", **dic)
from datetime import datetime
@app.template_filter("handle_time")
def handle_time(time):
'''
小于1分钟 => 刚刚
大于1分钟 小于1小时 => xx 分钟之前
大于1小时 小于24小时 => xx 小时之前
:param time:
:return:
'''
# 先判断传入的参数是不是 时间戳
if isinstance(time, datetime):
now = datetime.now()
# total_seconds() 得到具体的秒数
timestamp = (now - time).total_seconds()
if (timestamp < 60):
return "刚刚"
elif (timestamp < 60*60):
return f"{int(timestamp/60)} 分钟之前"
elif (timestamp < 60*60*24):
return f"{int(timestamp/60/60)} 小时之前"
else:
return time
if __name__ == '__main__':
app.run(debug=True)
<p>{{ now_time1|handle_time}}</p>
<p>{{ now_time2|handle_time}}</p>
<p>{{ now_time3|handle_time}}</p>