1 MVT
1. 1 Model
# 模型-model
# 通过框架特定orm框架工具sqlalchemy(flask_sqlalchemy) 与数据库交互
1.2 View
# 视图-view
# app.route()的修饰的函数方法
# 根据路由url处理相应的业务逻辑 返回相应结果
app = Flask(__name__)
@app.route('/')
def test():
return "flask_test..."
# test则为视图函数
1.2.1 get
# get请求多用于获取数据
@app.route("/get_data", methods=["GET"]) # 可指定请求方式 默认为get
def test():
return "GET 请求"
1.2.2 post
#post请求多用于表单提交数据
@app.route("/post_data", methods=["POST"]) # 指定为post请求
def post():
a1 = request.json.get('aa')
a2 = request.json.get('bb')
if ([a1, a2]):
ret = {'status': 200, 'msg': "ok"}
return jsonify(ret) # 返回类型多为json格式
1.2.3 区别
# 作用
get 获取数据
post 提交数据
# 携带数据
get携带数据 对url长度有限制 存放少量数据 且不安全
post放置在请求体内 长度不限 可存放大量数据 较安全
1.3 Templates
# 模板-template
# 存放相关的模板文件(html) 静态资源(js css)文件
# app = Flask(__name__, static_folder="static",static_url_path="",template_folder="templates")
# __name__:确定flask应用加载目录 其他资源加载目录
# static_folder:确定静态资源存放目录(css ,js)
# static_url_path:确定静态资源加载路径->/static/<filename>/
# template_folder:确定模板文件加载目录 flask框架默认jinjia2模板引擎

2 蓝图
2.1 BluePrint
BluePrint 是 Flask 提供的一个类,它具备 Flask 核心对象的很多功能,其中最重要的就是注册路由,我们通过蓝图,可以将视图函数根据不同的功能拆分到不同的模块中,从而实现对视图函数的模块化管理与开发 同时也支持模板文件 静态资源独立加载 但是蓝图不可独立运行 必须依附于flask应用
from flask import Blueprint
# 蓝图创建+配置
a_blue = Blueprint('蓝图名',
__name__,
static_folder=None,
static_url_path=None,
template_folder=None,
url_prefix=None)
# __name__:蓝图所在模块名 即应用加载的目录
# static_folder:静态资源目录
# static_url_path:静态资源加载路由url
# template_folder:模板文件加载目录
# url_prefix: url前缀 区别其他蓝图或者url同名 访问url会加上前缀
# 独立路由匹配
@a_blue.route('/aa')
def test():
return 'aa'
# 注册蓝图 否则无法使用
app.register_blueprint(a_blue, url_prefix="") # 建议在注册蓝图时进行url前缀添加
2.2 Blueprint实例
#----static/css/home.css
h1{
color: blue;
}
#-----------------------------------------------------------------------
#----static/css/test/home.css
h1{
color:red;
}
#-----------------------------------------------------------------------
#----templates/home.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<link rel="stylesheet" type="text/css" href="/static/css/home.css">
<title>Home</title>
</head>
<body>
<h1>flask应用模板文件</h1>
</body>
</html>
#-----------------------------------------------------------------------
#----templates/test/home.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<link rel="stylesheet" type="text/css" href="/static/css/test/home.css">
<title>蓝图模板文件</title>
</head>
<body>
<h1>蓝图模板文件</h1>
</body>
</html>
#-----------------------------------------------------------------------
#----views/views.py
from flask import render_template
from views import test_blu
# 路由匹配
@test_blu.route("/")
def test():
return render_template('test/home.html')
#-----------------------------------------------------------------------
#----views/__init__.py
from flask import Blueprint
# 创建蓝图
test_blu = Blueprint('test_blu', __name__,)
# 蓝图关联views
from . import views
#-----------------------------------------------------------------------
#----main.py
from flask import Flask, render_template
from views import test_blu
app = Flask(__name__)
@app.route('/')
def index():
return render_template('home.html')
# 注册蓝图
app.register_blueprint(test_blu, url_prefix="/test") # 添加url前缀
if __name__ == '__main__':
app.run(debug=True)

3 Cookie
3.1 cookie
cookie是存储在浏览器的一段纯文本信息 用于网站访问过程中用户身份辨别 进行会话追踪 在用户浏览器中存储数据(非敏感隐私数据)
Cookie是由服务器端生成,发送给客户端浏览器,浏览器会将Cookie的key:value保存,下次请求同一网站时就发送该Cookie给服务器(前提是浏览器设置为启用cookie)
Cookie的key:value可以由服务器端自己定义
Cookie放置在请求头部 cookie: key=value
3.2 cookie实例
from flask import Flask, make_response, request
app = Flask(__name__)
@app.route('/')
@app.route('/set_cookie')
def set_cookie():
# 构造响应对象
response = make_response('Flask-Cookie 测试')
# 添加cookie信息
# 设置过期时间:max_age(s:秒) or expires
# 没有设置过期时间 默认浏览器关闭则过期
# expires_time = datetime.datetime.now() + datetime.timedelta(seconds=10)
response.set_cookie('name', 'fsh', max_age=30, expires=None)
response.set_cookie('password', '666666', max_age=30)
return response
@app.route('/get_cookie')
def get_cookie():
"""获取cookie"""
try:
cookie_name = request.cookies.get('name')
cookie_psw = request.cookies.get('password')
ret = cookie_name + cookie_psw
except:
ret = "cookie不存在"
return ret
@app.route('/delete_cookie')
def delete_cookie():
"""删除cookie"""
response = make_response("delete_cookie")
response.delete_cookie('name')
response.delete_cookie('password')
return response
if __name__ == '__main__':
app.run(debug=True)
# cookie信息用于标记用户行为 以key:value形式保存在请求头部信息
# cookie保存在浏览器 明文保存 不建议使用隐私数据
# 添加cookie时设置参数
# response.set_cookie('k', 'v', max_age, expires, domain, path)
# domain:cookie作用域名 path:cookie有效路径
# 添加cookie 多用于用户登录注册进行标记 或是未登录状态购物车信息临时保存
# 获取cookie 操作多是用于判断用户是否登录 或是权限设定
# 删除cookie 多是用户退出登录时操作

4 Session
4.1 session
session机制 将session信息加密 于服务器生成session数据并存储 在cookie内部(key=session_id|session)备份用于请求验证用户状态
session 默认采用base64加密数据 存储在cookie中
session 底层实则是使用itsdangerous模块进行加密签名
4.2 session实例
import datetime
from flask import Flask, session
app = Flask(__name__)
# session需要配置密钥
app.config['SECRET_KEY'] = "1"
@app.route('/')
@app.route('/set_session')
def set_session():
session['name'] = 'fsh'
session['psw'] = '666666'
# 手动设置session过期时间
session.permanent = True
app.permanent_session_lifetime = datetime.timedelta(seconds=30)
return "set_session:success"
@app.route('/get_session')
def get_session():
try:
name = session.get('name')
psw = session.get('psw')
print(name, psw)
ret = name + str(psw)
except:
ret = 'session not exist'
return ret
@app.route('/delete_session')
def delete_session():
session.pop('name') # 单独删除一个
session.pop('psw')
# session.clear() # 全部清空
return 'session delete:success'
if __name__ == '__main__':
app.run(debug=True)

4.3 cookie与session
session: 用于跟踪用户行为状态标识数据 加密 数据可存储在集群服务器 数据库 文件 session依附cookie使用
cookie: 标识用户状态 默认不加密 存储在浏览器
4.4 session 实质
# session实质itsdangerous加密解密过程
import itsdangerous
import hashlib
def create_session():
"""session生成机制"""
secret_key = "1" # 类似加盐操作
t = itsdangerous.TimedJSONWebSignatureSerializer(secret_key, expires_in=60)
session_data = {'name': 'fsh', 'psw': '666666'}
# 加密 编码
hash_res = t.dumps(str(session_data)+secret_key)
session_value = hash_res.decode()
print("加密生成的session:\n", session_value)
# 解密
res = t.loads(session_value)
print("解密session数据:\n", res)
def md5_secret():
"""md5加密"""
salt = "1" # 加盐
ret = {'name': 'xyz', 'psw': '999999'}
ret = str(ret) + salt
# 生成md5对象
md5_o = hashlib.md5()
# 加密数据
md5_o.update(ret.encode('utf-8'))
md5_data = md5_o.hexdigest()
print('md5加密数据:\n', md5_data)
create_session()
md5_secret()
# itsdangerous内部默认使用了HMAC和SHA1来签名,基于 Django 签名模块。它也支持JSON Web 签名 (JWS)。这个库采用BSD协议
# session:eyJuYW1lIjoiZnNoIiwicHN3Ijo2NjY2NjZ9.X6HxLg.rKTmUnf5HQ3Zs3wpxgqT8oqyct8
# session = 会话数据 + 时间戳 + 加密哈希值(结合会话数据+事件戳+私钥hash)
# session= session_data . timestamp . Hash_value
# itsdangerous 多用于身份签名加密验证
# 应用JWT (jSON WEB TOKEN) || session
# 扩展md5加密:实质就是把任意长度的字符串进行十六进制转换称数字串
5 请求钩子
5.1 钩子类型
# 钩子函数:在执行函数与目标函数间实现挂载 重处理
# before_first_request 程序第一次请求调用 做程序初始化
# before_request 每次请求前调用 做参数验证
# after_request 处理请求后调用 做响应结果再处理
# teardown_request 每次请求后调用 对服务器错误信息监控
5.2 实例应用
from flask import Flask, request
app = Flask(__name__)
@app.before_first_request
def before_first_request():
print('--------before_first_request-----------')
print('程序应用第一次请求前调用,用于初始化数据库等其他配置信息')
@app.before_request
def before_request():
if request.cookies.get('name', None):
pass
print('--------before_request-----------')
print('每次请求前调用(已有请求), 可对请求参数进行校验\
不成功可以在这返回响应结果 这样就不会执行视图函数')
@app.after_request
def after_request(response):
"""必须返回一个响应对象"""
print('--------after_request-----------')
print('执行完视图函数调用,可对响应结果做进一步处理')
response.headers['Content-Type'] = 'application/json'
return response
@app.teardown_request
def teardown_request(e):
"""必须携带一个参数用于描述报错信息"""
print('--------teardown_request-----------')
print('每次请求后调用,接收服务器出错的参数')
print('异常信息e:', e) if e else print(None)
@app.route('/')
def test():
print('--------视图函数执行-----------')
return '视图执行结束...'
if __name__ == '__main__':
app.run(debug=True)

6 上下文
上下文相当于一个容器 保存flask运行过程中的一些信息
application context(应用上下文): current_app g
current_app:当前flask应用实例
g:用于存储全局数据 每次请求会重置 专用于保存用户数据
requset context(请求上下文): request session
request:通过关联flask应用获取的request对象 保存http请求内容request.args等
session:标记请求之间特殊的数据 使用cookie实现 保存用户会话信息
application->Flask(__name__)实例
request->每次http请求request实例
应用上下文:存储应用程序中的变量(配置信息 连接数据库信息 flask应用信息等)
请求上下文: 存储客户端与服务器交互数据session['k'] = v
应用上下文相当于请求上下文对flask应用的代理 帮助请求上下文关联flask
6.1 请求上下文
6.1.1 request
from flask import request
1.request.form 获取表单数据
2.request.args 获取url?参数
3.request.cookies 获取cookies数据
4.request.headers 获取请求头部信息
5.request.files 获取上传文件
6.request.method 获取请求方式get|post|put|delete...
7.request.url 获取请求url
8.request.json 获取json格式数据(content-ttype:application/json)
9.request.path 获取路由地址
from flask import Flask, request
app = Flask(__name__)
@app.route('/')
def test():
ret = {'url': request.url,
'path': request.path,
'method': request.method,
}
return ret
'''
{
"method": "GET",
"path": "/",
"url": "http://127.0.0.1:5000/"
}
'''
if __name__ == '__main__':
app.run(debug=True)
6.1.2 session
from flask import Flask, session
from werkzeug.test import EnvironBuilder
app = Flask(__name__)
app.config['SECRET_KEY'] = "1"
with app.request_context(EnvironBuilder(base_url="http://127.0.0.1:5000/").get_environ()):
session['name'] = 'fsh'
print("测试环境(手动加载请求上下文环境)\nsession_value=", session.get('name'))
6.2 应用上下文
6.2.1 current_app
from flask import Flask, current_app
app = Flask(__name__)
with app.app_context():
"""手动加载应用上下文环境"""
print("current_app.name=", current_app.name)
"""
只能在请求期间使用current_app获取应用相关信息
否则抛出异常:RuntimeError: Working outside of application context
"""
6.2.2 g
from flask import Flask, g
app = Flask(__name__)
@app.before_request
def prepare_g():
g.flag = 1
@app.route('/test1')
def test1():
return "test1---:{}".format(g.flag)
@app.route('/test2')
def test2():
g.flag = 2
return 'test2---:{}'.format(g.flag)
if __name__ == '__main__':
app.run(debug=True)
7 CSRF
7.1 csrf描述
csrf(cross sit request forgery) 跨站请求伪造
csrf指攻击者盗用了你的身份cookie数据 以你的名义发送恶意请求
包括:以你名义发送邮件 发消息 盗取你的账号
造成的问题:个人隐私泄露以及财产安全

7.2 csrf解决
7.2.1 session_hidden_hash_value
#----templates/e.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>信任页面</title>
</head>
<body>
<h1>信任页面</h1>
<form method="post">
{# 添加隐藏数据csrf 用于用户身份信息保护 #}
<input type="hidden" name="csrf" value={{ csrf }}>
<label>用户名:</label><input type="text" name="username" placeholder="请输入用户名"><br/>
<label>密码:</label><input type="password" name="password" placeholder="请输入密码"><br/>
<input type="submit" value="操作">
</form>
</body>
</html>
#----e.py
import hashlib
import time
from flask import Flask, request, render_template, session
app = Flask(__name__)
app.config["SECRET_KEY"] = "1"
@app.route('/', methods=["GET", "POST"])
def test():
if request.method == "GET":
# 使用md5加密一个隐藏数据保存到前端页面
# 且保存在session 用于提交数据(post请求)验证
md5_o = hashlib.md5()
md5_o.update(str(time.time()).encode('utf-8'))
csrf_hash_value = md5_o.hexdigest()
session['csrf'] = csrf_hash_value
return render_template('e.html', csrf=csrf_hash_value)
elif request.method == "POST":
session_csrf = session.get('csrf') # 保存在服务端csrf
form_csrf = request.form.get('csrf')
print(session_csrf, '\n', form_csrf)
if session_csrf != form_csrf:
return "身份验证失败, 无法进行下一步操作"
return "身份验证成功"
if __name__ == '__main__':
app.run(debug=True)
7.2.2 flask_wtf
$pip install flask_wtf
#----templates/f.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>伪造页面</title>
</head>
<body>
<form method="post">
<input type="hidden" name="csrf_token" value={{ csrf_token() }}>
<label>取款金额:</label><input type="text" name="money" placeholder="请输入提现金额"><br/>
<label>密码:</label><input type="password" name="password" placeholder="请输入密码"><br/>
<input type="submit" value="提现">
</form>
</body>
</html>
#----f.py
from flask import Flask, render_template, request, make_response
from flask_wtf import CSRFProtect
app = Flask(__name__)
app.config['SECRET_KEY'] = "2"
# flask 加载csrf防范机制:对所有视图(generate_csrf(secret_key=None, token_key=None)
CSRFProtect(app)
@app.route('/test', methods=["GET", "POST"])
def test():
if request.method == "GET":
return render_template('f.html')
elif request.method == "POST":
return '提现成功'
if __name__ == '__main__':
app.run(debug=True)

8 分页器
8.1 常规分页
page_size =1 # 每页数据
page_n = 2 # 当前页码
Tag.query.filter().limit(per_size).offset((per_size-1)*per_size)
# limit 限制输出量(输出多少个数据)
# offset 限制偏移量(从第几个数据开始输出)
8.2 paginate()
# 实际使用: paginate = Tag.query.filter().paginate(偏移量, 取出量)
paginate属性
has_prev: 是否有上一页
has_next: 是否有下一页
prev_num: 上一页页码
next_num: 下一页页码
page: 当前页码
pages: 总页数
per_page: 每一页数据量
items: 当前页查询对象集
iter_pages():迭代分页
8.3 实例
#----home.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<link rel="stylesheet" href="/static/css/jquery.pagination.css">
<script type="text/javascript" src="/static/js/jquery-1.12.4.min.js"></script>
<script type="text/javascript" src="/static/js/jquery.pagination.min.js"></script>
<title>Home</title>
</head>
<body>
{# 数据展示 #}
<div>
{% for d in data %}
<p>{{ d.get('id') }}</p>
<p>{{ d.get('name') }}</p>
<p>{{ d.get('content') }}</p>
{% endfor %}
</div>
{# 分页 #}
<div id="pagination" class="page">
<div class="ui-pagination-container">
<a href="{{ url_for('index') }}?page=1" class="ui-pagination-page-item" >首页</a>
{% if paginate.has_prev%}
<a href="{{ url_for('index') }}?page={{ paginate.prev_num }}" class="ui-pagination-page-item" >上一页</a>
{% endif %}
{% for num in paginate.iter_pages() %}
{% if num == paginate.page %}
<a href="#" class="ui-pagination-page-item active" >{{ num }}</a>
{% elif num %}
<a href="{{ url_for('index') }}?page={{ num }}" class="ui-pagination-page-item" >{{ num }}</a>
{% endif %}
{% endfor %}
{% if paginate.has_next%}
<a href="{{ url_for('index') }}?page={{ paginate.next_num }}" class="ui-pagination-page-item" >下一页</a>
{% endif %}
<a href="{{ url_for('index') }}?page={{ paginate.pages }}" class="ui-pagination-page-item" >尾页</a>
</div>
</div>
</body>
</html>
#---------------------------------------------------------------------
#----main.py
from flask import Flask, render_template, request
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
# 配置数据库(前提:create database flask charset=utf8;)
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql+pymysql://用户:密码@localhost:3306/flask?charset=utf8'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
# db关联app
db = SQLAlchemy(app)
# 模型类
class News(db.Model):
id = db.Column(db.Integer, primary_key=True)
title = db.Column(db.String(50), nullable=False)
content = db.Column(db.Text, nullable=False)
def get_data(self):
data = {
'id': self.id,
'title': self.title,
'content': self.content
}
return data
# 创建表
# db.create_all()
# 添加数据
@app.route('/')
def index():
# 获取请求参数page
page = request.args.get("page", 1)
page_num = 1
# 实例paginate
paginate = db.session.query(News).paginate(int(page), page_num, False)
# 数据
data = [d.get_data() for d in paginate.items]
return render_template('home.html', paginate=paginate, data=data)
if __name__ == '__main__':
app.run(debug=True)
#----jquery.pagination.css
.ui-pagination-container {
height: 34px;
line-height: 34px;
}
.ui-pagination-container .ui-pagination-page-item {
font-size: 14px;
padding: 4px 10px;
background: #fff;
border: 1px solid #c5b7b7;
color: #888;
margin: 0 3px;
text-decoration: none;
}
.ui-pagination-container .ui-pagination-page-item:hover {
border-color: #568dbd;
color: #568dbd;
text-decoration: none;
}
.ui-pagination-container .ui-pagination-page-item.active {
background: #568dbd;
border-color: #568dbd;
color: #fff;
cursor: default;
}
//----jquery-1.12.4.min.js 下载:https://www.jb51.net/zt/jquerydown.htm
//----jquery.pagination.min.js
!function(t,a,e,i){var n=function(a,e){this.ele=a,this.defaults={currentPage:1,totalPage:10,isShow:!0,count:5,homePageText:"首页",endPageText:"尾页",prevPageText:"上一页",nextPageText:"下一页",callback:function(){}},this.opts=t.extend({},this.defaults,e),this.current=this.opts.currentPage,this.total=this.opts.totalPage,this.init()};n.prototype={init:function(){this.render(),this.eventBind()},render:function(){var t=this.opts,a=this.current,e=this.total,i=this.getPagesTpl(),n=this.ele.empty();this.isRender=!0,this.homePage='<a href="javascript:void(0);" class="ui-pagination-page-item" data-current="1">'+t.homePageText+"</a>",this.prevPage='<a href="javascript:void(0);" class="ui-pagination-page-item" data-current="'+(a-1)+'">'+t.prevPageText+"</a>",this.nextPage='<a href="javascript:void(0);" class="ui-pagination-page-item" data-current="'+(a+1)+'">'+t.nextPageText+"</a>",this.endPage='<a href="javascript:void(0);" class="ui-pagination-page-item" data-current="'+e+'">'+t.endPageText+"</a>",this.checkPage(),this.isRender&&n.html("<div class='ui-pagination-container'>"+this.homePage+this.prevPage+i+this.nextPage+this.endPage+"</div>")},checkPage:function(){var t=this.opts,a=this.total,e=this.current;t.isShow||(this.homePage=this.endPage=""),1===e&&(this.homePage=this.prevPage=""),e===a&&(this.endPage=this.nextPage=""),1===a&&(this.homePage=this.prevPage=this.endPage=this.nextPage=""),a<=1&&(this.isRender=!1)},getPagesTpl:function(){var t=this.opts,a=this.total,e=this.current,i="",n=t.count;if(a<=n)for(g=1;g<=a;g++)i+=g===e?'<a href="javascript:void(0);" class="ui-pagination-page-item active" data-current="'+g+'">'+g+"</a>":'<a href="javascript:void(0);" class="ui-pagination-page-item" data-current="'+g+'">'+g+"</a>";else{var s=n/2;if(e<=s)for(g=1;g<=n;g++)i+=g===e?'<a href="javascript:void(0);" class="ui-pagination-page-item active" data-current="'+g+'">'+g+"</a>":'<a href="javascript:void(0);" class="ui-pagination-page-item" data-current="'+g+'">'+g+"</a>";else{var r=Math.floor(s),h=e+r,o=e-r,c=n%2==0;h>a&&(c?(o-=h-a-1,h=a+1):(o-=h-a,h=a)),c||h++;for(var g=o;g<h;g++)i+=g===e?'<a href="javascript:void(0);" class="ui-pagination-page-item active" data-current="'+g+'">'+g+"</a>":'<a href="javascript:void(0);" class="ui-pagination-page-item" data-current="'+g+'">'+g+"</a>"}}return i},setPage:function(t,a){return t===this.current&&a===this.total?this.ele:(this.current=t,this.total=a,this.render(),this.ele)},getPage:function(){return{current:this.current,total:this.total}},eventBind:function(){var a=this,e=this.opts.callback;this.ele.off("click").on("click",".ui-pagination-page-item",function(){var i=t(this).data("current");a.current!=i&&(a.current=i,a.render(),e&&"function"==typeof e&&e(i))})}},t.fn.pagination=function(t,a,e){if("object"==typeof t){var i=new n(this,t);this.data("pagination",i)}return"string"==typeof t?this.data("pagination")[t](a,e):this}}(jQuery,window,document);

9 全局异常捕获
# 全局异常捕获404
app = Flask(__name__)
@app.errorhandler(404)
def error(e):
return "404页面"
# 返回404错误页面
# return render_template('404.html'), 404
# 在整个flask项目均应用
10 路由转换器
10.1 内置路由转换器
DEFAULT_CONVERTERS = {
'default': UnicodeConverter,
'string': UnicodeConverter,
'any': AnyConverter,
'path': PathConverter,
'int': IntegerConverter,
'float': FloatConverter,
'uuid': UUIDConverter,
}
app = Flask(__name__)
@app.route('/test/<int:data>')
def test(data):
return "test-data:%d" % data
10.2 自定义路由转换器
from flask import Flask, redirect, url_for
from werkzeug.routing import BaseConverter
# 创建flask实例
app = Flask(__name__)
# 自定义路由管理器
class MyConverter(BaseConverter):
"""重写init方法"""
def __init__(self, map, regular):
print("__init__调用")
print(map, regular)
super(MyConverter, self).__init__(map)
self.regex = regular
def to_python(self, value):
"""
1.匹配数据时调用to_python
2.to_python value 实际决定匹配的值
:param value:
:return:
"""
print("to_python调用")
print(type(value), value)
value = "55"
return value
def to_url(self, value):
"""
1.url_for操作会调用to_url
2.参数匹配成功后也会调用to_url
:param value:
:return:
"""
print('to_url调用')
print(type(value), value)
value = "66"
return value
# 添加路由转换器
app.url_map.converters['r'] = MyConverter
@app.route("/test/<r('[0-9]+'):data>")
def test(data):
return "test_data: %s" % data
@app.route("/")
def test1():
return redirect(url_for('test', data='33'))
# 获取路由表
print(app.url_map)
if __name__ == "__main__":
app.run(debug=True)

文档