Flask 2 框架进阶
一 请求与响应
请求属性与方法
request.method 请求方法
request.args get请求提交的数据
request.form post请求提交的数据
request.values post和get提交的数据总和
request.cookies 客户端所带的cookie
request.headers 请求头
request.path 不带域名,请求路径
request.full_path 不带域名,带参数的请求路径
request.url 带域名带参数的请求路径
request.base_url 带域名请求路径
request.url_root 域名
request.host_url 域名
request.host 127.0.0.1:500
request.files 请求提交的文件
requst对象的常用方法
request对象使用需要从flask模块中导入
Copyfrom flask import Flask, request
使用request属性获取url
属性 | 解析值 | 属性 | 解析值 |
---|---|---|---|
path | u‘/student_list/’ | base_url | u'http://127.0.0.1:5000/student_list/' |
full_path | u‘/student_list/?name=mark’ | url | u'http://127.0.0.1:5000/student_list/?name=mark' |
host | u'127.0.0.1:5000' | url_root | u'http://127.0.0.1:5000/' |
host_url | u'http://127.0.0.1:5000/' |
request的解析结果如下。
Copy@app.route('/student_list/')
def student_list():
print(request.path) # 输出 /student_list/
print(request.full_path) # 输出 /student_list/?name=mark
print(request.host) # 输出 127.0.0.1:5000
print(request.host_url) # 输出 http://127.0.0.1:5000/
print(request.base_url) # 输出 http://127.0.0.1:5000/student_list/
print(request.url) # 输出 http://127.0.0.1:5000/student_list/?name=mark
print(request.url_root) # 输出 http://127.0.0.1:5000/
return 'request.urldemo测试'
其他request对象常用的属性和方法。
GET和POST:
常见的HTTP方法:
请求 | 说明 | 请求 | 说明 |
---|---|---|---|
GET | 获取服务器资源 | DELETE | 删除服务器资源 |
POST | 处理服务器资源 | PATCH | 在服务器更新资源(客户端提供改变的属性) |
PUT | 在服务器更新资源(客户端提供改变后的完整资源) |
一般常用的请求为GET和POST
GET
请求:
GET请求一般用于在服务器上获取资源,不会更改服务器的状态。
GET实例:
Copy@app.route('/', methods=['GET']) # 不写methods也可以 默认就接收get请求
def demo_get():
print(request.args.get('name')) # 输出 mark
return '{}请求'.format(request.method)
结合request对象,使用request.args属性获取get传来的参数
关键词:
- 使用request.args属性获取get传来的参数,
- @app.route('/', methods=['GET']) 指定浏览器只能以GET方法访问服务端。
POST
请求:
POST 请求: 会给服务器提交一些数据或者文件,会对服务器的状态产生影响。
Copyfrom flask import Flask, request, render_template
import config
app = Flask(__name__)
@app.route('/login_request/',methods=['POST'])
def login_request():
print(request.form.get('username')) # 'mark'
print(request.form.get('password')) # '123'
if request.form.get('username') == 'mark' and request.form.get('password') == '123':
return 'success'
else:
return 'error'
@app.route('/login/',methods=['GET'])
def login():
return render_template('login.html')
if __name__ == '__main__':
app.run()
关键词:
- request.form是专门用来针对表单取数据的,在这里如果前端是以表单的形式提交的,我们可以使用request.form来取值
- @app.route() 中的 methods=['POST'] 代表只接收浏览器的POST请求
templates/login.html
Copy<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>登录界面</title>
</head>
<body>
<form action="/login_request/" method="POST">
用户:<input type="text" name="username">
密码:<input type="text" name="password">
<input type="submit" value="提交">
</form>
</body>
</html>
总体的逻辑是 :
- 首先访问127.0.0.1:5000/login/,默认是get请求。
- 然后
return render_template('login.html')
返回给浏览器页面。 - 然后填写内容点击提交,以post方式请求 http://127.0.0.1:5000/login_request/。
- 然后进入
def login_request()
视图函数 进行逻辑判断返回成功与否。
一个视图函数同时可以接收GET和POST请求
实例:
server.py:
Copyfrom flask import Flask, request, render_template
import config
app = Flask(__name__)
@app.route('/login_inner/',methods=['POST','GET'])
def login_inner():
if request.method == 'GET': #判断本次请求是否为get请求
return render_template('login.html')
if request.form.get('username') == 'mark' and request.form.get('password') == '123':
return 'success'
return 'error'
if __name__ == '__main__':
app.run(debug=True)
关键词:
@app.route()
的methods
方法 指定该视图函数接收浏览器传过来的请求方法,可以指定多个。request.method
获取字符串格式的请求方法
templates/login.html:
Copy<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>登录界面</title>
</head>
<body>
<form action="" method="POST">
用户:<input type="text" name="username">
密码:<input type="text" name="password">
<input type="submit" value="提交">
</form>
</body>
</html>
请求扩展方法
类似于django的中间件,请求来时,请求走时,做什么操作
# 1 请求来了就会触发,类似于django的process_request,如果有多个,顺序是从上往下
@app.before_request
def before(*args,**kwargs):
if request.path=='/login':
return None
else:
name=session.get('user')
if not name:
return redirect('/login')
else:
return None
# 2 请求走了就会触发,类似于django的process_response,如果有多个,顺序是从下往上执行
@app.after_request
def after(response):
print('我走了')
return response
#3 before_first_request 项目启动起来第一次会走,以后都不会走了,也可以配多个(项目启动初始化的一些操作)
@app.before_first_request
def first():
print('我的第一次')
# 4 每次视图函数执行完了都会走它,# 用来记录出错日志
@app.teardown_request # 用来记录出错日志
def ter(e):
print(e)
print('我是teardown_request ')
# 5 errorhandler绑定错误的状态码,只要码匹配,就走它
@app.errorhandler(404)
def error_404(arg):
return render_template('error.html',message='404错误')
# 6 全局标签
@app.template_global()
def sb(a1, a2):
return a1 + a2
# 在模板中:{{ sb(3,4) }}
# 7 全局过滤器
@app.template_filter()
def db(a1, a2, a3):
return a1 + a2 + a3
# 在模板中{{ 1|db(2,3)}}
1 重点掌握before_request和after_request,
2 注意有多个的情况,执行顺序
3 before_request请求拦截后(也就是有return值),response所有都执行
二 视图函数和视图类
视图函数
基本用法与Django的视图函数类似,返回结果时需要注意
# 响应格式
# return "字符串"
# return render_template('html模板路径',**{})
# return redirect('/index.html')
# django有JsonResponse对应的flask有jsonify
# return jsonify({'k1':'v1'})
设置cookie
aa='hello world'
res=make_response(aa)
res.set_cookie('xxx','lqz')
往响应头中放属性
res.headers['X-Something'] = 'A value'
反向解析
url_for()的使用
当设置别名时url_for()会根据别名调用视图函数
url_for('视图函数名字') # 输出该视图函数url
具体例子:
from flask import Flask,url_for
app = Flask(__name__)
app.config.update(DEBUG=True)
@app.route('/')
def demo1():
print(url_for("book")) # 注意这个引用的是视图函数的名字 字符串格式
print(type(url_for("book")))
return url_for("book")
@app.route('/book_list/')
def book():
return 'flask_book'
if __name__ == "__main__":
app.run()
视图函数如果需要参数,在使用url_for调用时传入所需的参数
@app.route('/demo2/')
def demo2():
student_url = url_for('student', id=5, name='mark') # id 就是动态path的key 必须赋值, # name 将作为查询字符串传入
print(student_url)
return student_url
@app.route('/student/<int:id>/')
def student(id):
return 'student {}'.format(id)
视图函数添加自定义装饰器
我们在平时的开发的过程中,很多需要权限验证的功能需要用到装饰器,下面的代码是如何在flask中实现一个装饰器。
from flask import Flask, request
from functools import wraps
app = Flask(__name__)
def login_verify(func):
@wraps(func)
def wrapper(*args, **kwargs):
user_name = request.args.get('user')
password = request.args.get('password')
if user_name == 'mark' and password == '123':
return func(*args,**kwargs)
else:
return '请登录'
return wrapper
@app.route('/')
def hello_world():
return 'Hello World!'
@app.route('/my_info/')
@login_verify
def my_info():
return '个人信息页面'
关键词:
- 装饰器一定要写在注册路由的下面,写在视图函数的上面。
- 装饰器内部一定要使用
@wraps(func)
方法,用于保护被装饰函数的属性。
视图类
视图类的基本用法
from flask import Flask, views, request, url_for
from functools import wraps
def login_verify(func):
@wraps(func)
def wrapper(*args, **kwargs):
user_name = request.args.get('user')
password = request.args.get('password')
if user_name == 'mark' and password == '123':
return func(*args,**kwargs)
else:
return '请登录'
return wrapper
class CBVTest(views.MethodView):
methods = ['GET','POST'] # 指定可以接收的方法有什么
decorators = [login_verify,] # 指定自定义的装饰器
def get(self):
print(url_for('cbvtest'))
return 'cbv_get'
def post(self):
return 'cbv_post'
app.add_url_rule('/cbvtest',view_func=CBVTest.as_view(name='cbvtest'),endpoint='end_demo')
详解:
-
首先从flask中导入
views
-
写一个类一定要继承
views.MethodView
-
在类中写
methods = ['GET','POST']
可以指定可接受的请求类型 -
在类中写
decorators = [login_verify,]
可以指定装饰器,第一个装饰器是最里层函数依次往后包裹 -
在类中写
def get(self):
用于获取get请求 -
在类中写
def post(self):
用于获取post请求 -
添加路由的方法使用
app.add_url_rule( '路由',view_func=CBVTest.as_view(name='自定义一个端点名字'))
其原理是
CBVTest.as_view(name='自定义一个端点名字')
会返回一个函数,name是为这个函数命的名字,可以通过这个函数进行分发请求等操作。
三 flask模板引擎jinja2
模板引擎
实现视图的业务逻辑和返回给前端的页面逻辑分离的工具,我们称之为模板引擎。
模板可以理解为一个特殊的html
文件,特殊之处就在于这个html
文件包含固定内容和动态部分,其动态部分可以借助模板引擎进行传参
模板引擎帮我们分开了业务逻辑和页面逻辑,并且我们每次修改一个大字符串会非常不方便。模板引擎还可以读取并执行模板中的特殊语法标记,并根据传入的数据将变量替换为实际值,然后返回给浏览器,这个过程我们称之为渲染。
作用:辑和页面逻辑的分离,实现了动态的去渲染页面。
Flask
使用jinja2
作为框架的默认模板引擎,Jinja2
是基于python
的模板引擎,功能比较类似于于PHP
的smarty
,J2ee
的Freemarker
和velocity
。Jinja2
除了设置变量,还允许我们在模板中添加if判断,执行for迭代,调用函数等,以各种方式控制模板的输出。并且jinja2
不限制模板的格式为html
,可以是任何格式的文本文件。
模板举例:
Copy<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>登录界面</title>
</head>
<body>
<h1>login01</h1> <!--login02.html文件的这一行的内容是:‘ <h1>login02</h1> ’ -->
<form action="" method="POST">
用户:<input type="text" name="username">
密码:<input type="text" name="password">
<input type="submit" value="提交">
</form>
</body>
</html>
模板引擎传参
模板引擎还可以读取并执行模板中的特殊语法标记,并根据传入的数据将变量替换为实际值,这个步骤我们就称之为模板引擎传参。
我们传参的时候要应用render_template()
利用render_template的第二个参数进行传参,该函数在定义时候,第二个参数是可变长形参,所以在传值的时候我们可以传入多个关键字实参。
在模板中接收的时候使用{{}}
包裹参数进行接收。
传参举例:
server.py
def demo2():
context_dict = {"name": "mark",
"age": "mark",
"sex": "girl",
"other_info":{"tel":1365,
"qq":565656}}
return render_template('index.html',**context_dict)
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>模板传参</title>
</head>
<body>
{{name}}
{{age}}
{{sex}}
{{other_info.tel}}
{{other_info["qq"]}}
</body>
</html>
在视图函数中
- render_template传参的时候以关键字实参进行传参。可以传多个,可以用**讲字典打散成关键字实参。
在模板中
- jinja2模板引擎支持接收变量在用
{{}}
包裹参数进行接收 - 并且如果发现是字典,可以用
.
字典里面的key取出value值。也可以直接字典跟[]
进行取值。
模板中反向解析
server.py
@app.route('/')
def index():
return render_template('index.html', name="mark", age=18)
@app.route('/info/')
def info():
return render_template('info.html')
info.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>信息页面</title>
</head>
<body>
<h1>这是信息页面</h1>
</body>
</html>
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>模板传参</title>
</head>
<body>
<a href="/info/">正常跳转</a>
<a href="{{ url_for('info') }}">urlfor跳转</a>
</body>
</html>
- url_for 在视图函数中如何使用,在模板中同样的用法。
- 支持翻转查询字符串
- 支持动态路由翻转
jinja2中控制语句
在jinja2中用{% %}
特殊符号来编辑控制语句,一个语句以{% ... %}
为起始 并且以{% end... %}
来标记结束。
逻辑语句
可以使用> , < , <=, ==,!=,
进行判断,
也可以使用 and,or,not,()
来进行逻辑合并
server.py
Copy...
@app.route('/')
def hello_world():
context_dict = {
'age': 17,
'sex': 'man',
}
return render_template('index.html',**context_dict)
...
index.html
Copy<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>jinja2分支</title>
</head>
<body>
{% if sex == 'man' %}
<p>男人</p>
{% else %}
<p>女人</p>
{% endif %}
{% if age > 18 %}
<p>成年人</p>
{% elif age == 18 %}
<p>刚刚成年</p>
{% else %}
<p>未成年</p>
{% endif %}
</body>
</html>
循环语句
for
循环可以便利任何一个可迭代对象,包括列表、字典等,支持反向遍历
列表循环:
{% for country in countrys%}
<p>{{ country }}</p>
{% else %}
<p>没有值</p>
{% endfor %}
sever.py
Copy@app.route('/')
def hello_world():
context_dict = {
'countrys':["1-china","2-America","3-French"]
}
return render_template('index.html',**context_dict)
index.html
Copy<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>for循环</title>
</head>
<body>
{% for country in countrys %} {# {% for country in countrys|reverse %} 可以实现反向遍历#}
<p>{{ country }}</p>
{% else %}
<p>没有值</p>
{% endfor %}
</body>
</html>
反向遍历实例
server.py`的 `{% for country in countrys %}` 改为 `{% for country in countrys|reverse %}
字典循环
sever.py
Copy@app.route('/')
def hello_world():
context_dict = {
'countrys':["1-china","2-America","3-French"]
}
return render_template('index.html',**context_dict)
@app.route('/demo/')
def demo():
context_dict ={
'colleges':[
{
'name': '清华大学',
'area': '北京'
},
{
'name': '复旦大学',
'area': '上海'
''
},
{
'name': '吉林大学',
'area': '吉林'
},
{
'name': '中山大学',
'area': '广东'
}
]
}
return render_template('index.html',**context_dict)
index.html
Copy<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>for循环</title>
</head>
<body>
<table>
<tr>
<th>1开始的序号</th>
<th>0开始的序号</th>
<th>大学名称</th>
<th>所属地区</th>
<th>总数</th>
</tr>
{% for college in colleges %}
{% if loop.first %}
<tr style="background: blue">
{% elif loop.last %}
<tr style="background: yellow ">
{% else %}
<tr>
{% endif %}
<td>{{ loop.index }}</td>
<td>{{ loop.index0 }}</td>
<td>{{ college.name }}</td>
<td>{{ college.area }}</td>
<td>{{ loop.length }}</td>
</tr>
{% endfor %}
</table>
</body>
</html>
for循环常用变量表
for循环常用变量 | 功能描述 |
---|---|
loop.index | 当前循环的索引(从1开始) |
loop.index0 | 当前循环的索引(从0开始) |
loop.first | 是否是第一次循环,是返回True,否则返回Flase |
loop.last | 是否是最后一次循环,是返回True,否则返回Flase |
loop.length | 总共可以循环的次数 / 迭代器的长度 |
for循环中的else用法
for还可以else分支语法,如果for内部没有遍历出来内容,那么就会走else分支,反之如果for循环遍历出了内容,则不会运行else分支。
注意:jinja2
中的for
和 else
逻辑不通于python
在此不要类比python中的 for
和 else
。
Copy{% for country in countrys|reverse %}
<p>{{ country }}</p>
{% else %}
<p>没有值</p>
{% endfor %}
模板加载静态文件
在模板中加载静态文件的时候也要使用到url_for()
函数,去寻找具体的静态文件资源。第一个参数是定位到static
文件夹,filename
参数定位到static文件夹内的具体资源。
Copy{{ url_for('static',filename='相对于static文件夹的路径') }}
项目目录:
Copy│ app.py
│
├─static # 文件夹
│ ├─css # 文件夹
│ │ demo.css
│ │
│ ├─images # 文件夹
│ │ 1.png
│ │
│ └─js # 文件夹
│ demo.js
│
├─templates # 文件夹
index.html
app.py
@app.route('/')
def hello_world():
return render_template('index.html')
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>静态文件加载</title>
<link rel="stylesheet" href="{{ url_for('static',filename='css/demo.css') }}">
<script src="{{ url_for('static',filename='js/demo.js') }}"></script>
</head>
<body>
<img src="{{ url_for('static',filename='images/1.png') }}">
</body>
</html>
demo.css
body{
background: red;
}
demo.js
alert('hello world')
模板的继承
jinja2的模板继承可以把一些公共的代码定义到一个基模板中,比如把导航栏、页脚等通用内容放在基模板中,以后所有的子模板直接继承基模板,在子模板被渲染时会自动包含继承基模板的内容,通过模板的继承可以避免在多个模板中编写重复的代码。
在基模板中定义一些公共的代码,子模板会继承这些公共的代码,但是子模板需要根据自己的需求去实现不同的代码,这个时候就需要在基模板中提供一些接口,以便子模板实现自己的业务需求。
1 基本写法
在基/父模板中定义接口(block)
Copy{% block main %} {# main是自定义的变量名 #}
{% endblock %}
在子模板中继承父模板,并且重写接口(block)
Copy{% extends 'base.html' %} {# extends 后面跟的参数是导入的基模板相对于templates的路径 #}
{% block main %}
{% endblock %}
2 子模板中调用父模板代码block中的代码
基模板中
Copy{% block main %}
<p>父模板中main中原有的内容</p>
{% endblock %}
子模板中:
Copy{% block main %}
{{ super() }} {# 保留基模板中本块的代码 #}
<p>子模板中重写main的内容 </p>
{% endblock %}
3 在子模板中调用其他block中的代码:
子模板中:
Copy{% block main %}
{{ self.demo() }} {# self.其他block名字 #}
<p>子模板中重写main的内容 </p>
{% endblock %}
4 子模板中的想定义自己的代码只能放到block中,否则无效
项目目录
Copy│ app.py
│
├─static # 文件夹
│ └─css
│ bootstrap-theme.css
│ bootstrap-theme.css.map
│ bootstrap-theme.min.css
│ bootstrap-theme.min.css.map
│ bootstrap.css
│ bootstrap.css.map
│ bootstrap.min.css
│ bootstrap.min.css.map
│
├─templates # 文件夹
base.html
detail.html
css文件夹: 是从我们上面下载好的用于生产环境的 Bootstrap
中解压出来的
base.html 注意:里面的form
标签中的内容和nav
标签中的内容均是bootstrap框架的代码截取,div
标签是用于清除浮动
Copy<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>父模板</title>
<link rel="stylesheet" href="{{ url_for('static',filename='css/bootstrap.css') }}">
</head>
<body>
<form class="navbar-form navbar-left" role="search">
<div class="form-group">
<input type="text" class="form-control" placeholder="Search">
</div>
<button type="submit" class="btn btn-default">Submit</button>
</form>
<div style=" visibility:hidden;display:block;font-size:0;clear:both;
height:50px"></div>
{% block main %}
<p>父模板中main中原有的内容</p>
{% endblock %}
<br>
<br>
<br>
{% block demo %}
<p>demo中原有的内容</p>
{% endblock %}
<div style=" visibility:hidden;display:block;font-size:0;clear:both;
height:0"></div>
<nav aria-label="Page navigation">
<ul class="pagination">
<li>
<a href="#" aria-label="Previous">
<span aria-hidden="true">«</span>
</a>
</li>
<li><a href="#">1</a></li>
<li><a href="#">2</a></li>
<li><a href="#">3</a></li>
<li><a href="#">4</a></li>
<li><a href="#">5</a></li>
<li>
<a href="#" aria-label="Next">
<span aria-hidden="true">»</span>
</a>
</li>
</ul>
</nav>
</body>
</html>
detail.html
Copy{% extends 'base.html' %}
{% block demo %}
<p>子模板中重写demo的内容</p>
{% endblock %}
{% block main %}
{{ super() }} {# 保留基模板中本block的代码 #}
{{ self.demo() }} {# 调用demo block的代码 #}
<p>子模板中重写main的内容 </p>
{% endblock %}
app.py 注意:app.config.update(TEMPLATES_AUTO_RELOAD=True)
语句用于每次都重新加载模板文件
Copyfrom flask import Flask, render_template
app = Flask(__name__)
app.config.update(TEMPLATES_AUTO_RELOAD=True)
@app.route('/')
def hello_world():
return render_template('base.html')
@app.route('/demo/')
def demo():
return render_template('detail.html')
if __name__ == '__main__':
app.run()
闪现
Flask 提供了一个非常简单的方法来使用闪现系统向用户反馈信息。闪现系统使得在一个请求结束的时候记录一个信息,然后在且仅仅在下一个请求中访问这个数据
,强调flask闪现是基于flask
内置的session
的,利用浏览器的session
缓存闪现信息。所以必须设置secret_key
。
server.py
Copyfrom flask import Flask, flash, redirect, render_template, \
request, url_for
app = Flask(__name__)
app.secret_key = 'some_secret'
@app.route('/')
def index():
return render_template('index.html')
@app.route('/login', methods=['GET', 'POST'])
def login():
error = None
if request.method == 'POST':
if request.form['username'] != 'admin' or \
request.form['password'] != '123':
error = '登录失败'
else:
flash('恭喜您登录成功')
return redirect(url_for('index'))
return render_template('login.html', error=error)
if __name__ == "__main__":
app.run()
注意:这个 flash()
就可以实现在下一次请求时候,将括号内的信息做一个缓存。不要忘记设置secret_key
这里是 index.html 模板:
Copy{% with messages = get_flashed_messages() %} # 获取所有的闪现信息返回一个列表
{% if messages %}
<ul class=flashes>
{% for message in messages %}
<li>{{ message }}</li>
{% endfor %}
</ul>
{% endif %}
{% endwith %}
<h1>主页</h1>
<p>跳转到登录页面<a href="{{ url_for('login') }}">登录?</a>
注意:{% with messages = get_flashed_messages() %} # 获取所有的闪现信息返回一个列表
这里是login.html 模板
Copy<h1>登录页面</h1>
{% if error %}
<p class=error><strong>Error:</strong> {{ error }}
{% endif %}
<form action="" method=post>
用户名:
<input type=text name=username>
密码:
<input type=password name=password>
<p><input type=submit value=Login></p>
</form>
简单的在模板中实现获取闪现信息小结:
设置闪现内容:flash('恭喜您登录成功')
模板取出闪现内容:{% with messages = get_flashed_messages() %}
模板中的分类闪现
当闪现一个消息时,是可以提供一个分类的。未指定分类时默认的分类为 'message'
。 可以使用分类来提供给用户更好的反馈,可以给用户更精准的提示信息体验。
要使用一个自定义的分类,只要使用 flash()
函数的第二个参数:
flash('恭喜您登录成功',"status")
flash('您的账户名为admin',"username")
在使用get_flashed_messages()
时候需要传入with_categories=true
便可以渲染出来类别
{% with messages = get_flashed_messages(with_categories=true) %}
{% if messages %}
<ul class=flashes>
{% for category, message in messages %}
<li class="{{ category }}">{{ category }}:{{ message }}</li>
{% endfor %}
</ul>
{% endif %}
{% endwith %}
模板中的分类闪现小结:
分类设置闪现内容:flash('恭喜您登录成功',"status")
flash('您的账户名为admin',"username")
模板取值: {% with messages = get_flashed_messages(with_categories=true) %}
{% if messages %}
<ul class=flashes>
{% for category, message in messages %}
...
模板中过滤闪现消息
同样要使用一个自定义的分类,只要使用 flash()
函数的第二个参数:
flash('恭喜您登录成功',"status")
flash('您的账户名为admin',"username")
在使用get_flashed_messages()
时候需要传入category_filter=["username"]
便可根据类别取出闪现信息。中括号内可以传入的值就是类别,可以传入多个。
{% with messages = get_flashed_messages(category_filter=["username"]) %}
{% if messages %}
<ul>
{%- for message in messages %}
<li>{{ message }}</li>
{% endfor -%}
</ul>
</div>
{% endif %}
{% endwith %}
小结:
分类设置闪现内容:flash('恭喜您登录成功',"status")
flash('您的账户名为admin',"username")
模板取值: % with messages = get_flashed_messages(category_filter=["username"]) %}
{% if messages %}
<ul>
{%- for message in messages %}
视图中获取闪现信息
-设置: flash('xxx')
-取值:get_flashed_message() # 注意这个不同于模板取值,这个是从flask中导入的
-注意:在视图中获取闪现信息不必非得是两次连续的请求,只要保证是第一次取相应的闪现信息,就可以取得到。
实例:
from flask import Flask, request, flash, get_flashed_messages
import os
app = Flask(__name__)
app.secret_key = os.urandom(4)
app.debug = True
@app.route('/login/')
def login():
if request.args.get('name') == 'rocky':
return 'ok'
flash('第一条闪现信息:用户名不是rocky填写的是{}'.format(request.args.get('name')))
# flash('第二条闪现信息:用户名不是rocky填写的是{}'.format(request.args.get('name')))
return 'error,设置了闪现'
@app.route('/get_flash/')
def get_flash():
#get_flashed_messages()是一个列表列表可以取出闪现信息,该条闪现信息只要被取出就会删除掉。
return '闪现的信息是{}'.format(get_flashed_messages())
@app.route('/demo/')
def demo():
return 'demo'
if __name__ == '__main__':
app.run()
小结:
- get_flashed_messages()是一个列表,该列表可以取出闪现信息,该条闪现信息只要被取出就会删除掉。
在视图中实现分类获取闪现信息
-设置:flash('用户名错误', "username_error")
flash('用户密码错误', "password_error") # 第二个参数为闪现信息的分类。
-取所有闪现信息的类别和闪现内容:get_flashed_messages(with_categories=True)
-针对分类过滤取值:get_flashed_messages(category_filter=['username_error'])
# 中括号内可以写多个分类。
-注意:如果flash()没有传入第二个参数进行分类,默认分类是 'message'
实例1
@app.route('/login/')
def login():
if request.args.get('name') == 'rocky':
return 'ok'
flash('用户名错误', category="username_error")
flash('用户密码错误', "password_error")
return 'error,设置了闪现'
@app.route('/get_flash/')
def get_flash():
return '闪现的信息是{}'.format(get_flashed_messages(with_categories=True))
实例2
@app.route('/login/')
def login():
if request.args.get('name') == 'rocky':
return 'ok'
flash('用户名错误', category="username_error")
flash('用户密码错误', "password_error")
return 'error,设置了闪现'
@app.route('/get_flash/')
def get_flash():
return '闪现的信息是{}'.format(get_flashed_messages(category_filter=['username_error']))