Flask 高级

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)



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)



文档

[1] Flask应用配置 https://dormousehole.readthedocs.io/en/latest/config.html

[2] Flask结构引荐 https://www.jb51.net/article/165992.htm

[3] csrf 解决 https://www.jianshu.com/p/bab9b45b46f6

[4] WSGI https://www.jianshu.com/p/679dee0a4193

posted @ 2020-11-09 08:52  爱编程_喵  阅读(102)  评论(0)    收藏  举报
jQuery火箭图标返回顶部代码

jQuery火箭图标返回顶部代码

滚动滑动条后,查看右下角查看效果。很炫哦!!

适用浏览器:IE8、360、FireFox、Chrome、Safari、Opera、傲游、搜狗、世界之窗.