5. Flask 信号和项目蓝图

Flask 信号和项目蓝图

信号(源码)

信号,是在flask框架中为我们预留的钩子,让我们可以进行一些自定义操作。

pip3 install blinker

根据flask项目的请求流程来进行设置扩展点

中间件
from flask import Flask, render_template

app = Flask(__name__, static_url_path='/yy')

@app.route('/index')
def index():
    return render_template('img.html')

@app.route('/order')
def order():
    return render_template('img.html')

class MyMiddleware(object):
    def __init__(self, old_app):
        self.wsgi_app = old_app.wsgi_app

    def __call__(self, *args, **kwargs):
        print('123')
        result = self.wsgi_app(*args, **kwargs)
        print('456')
        return result

app.wsgi_app = MyMiddleware(app)

if __name__ == '__main__':
    app.run()
* Serving Flask app '__main__'
 * Debug mode: off

WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
 * Running on http://127.0.0.1:5000
Press CTRL+C to quit
127.0.0.1 - - [20/May/2024 11:32:19] "GET / HTTP/1.1" 404 -

123
456

127.0.0.1 - - [20/May/2024 11:32:22] "GET /index HTTP/1.1" 200 -
127.0.0.1 - - [20/May/2024 11:32:22] "GET /yy/img/haha.png HTTP/1.1" 200 -

123
456
123
456
appcontext_pushed

当app_ctx被push到local中的栈之后,会触发appcontext_pushed信号,之前注册在这个信号中的方法,就会被执行。

from flask import Flask,render_template
from flask import signals

app = Flask(__name__, static_url_path='/yy')

@signals.appcontext_pushed.connect
def f1(arg):
    print('appcontext_pushed信号f1被触发',arg)

@signals.appcontext_pushed.connect
def f2(arg):
    print('appcontext_pushed信号f2被触发',arg)

@app.route('/')
def index():
    return render_template('img.html')

@app.route('/order')
def order():
    return render_template('img.html')

if __name__ == '__main__':
    app.run()
    # app.__call__
* Serving Flask app '__main__'
 * Debug mode: off

WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
 * Running on http://127.0.0.1:5000
Press CTRL+C to quit
127.0.0.1 - - [20/May/2024 11:54:29] "GET / HTTP/1.1" 200 -
127.0.0.1 - - [20/May/2024 11:54:29] "GET /yy/img/haha.png HTTP/1.1" 304 -

appcontext_pushed信号f2被触发 
appcontext_pushed信号f1被触发 
appcontext_pushed信号f2被触发 
appcontext_pushed信号f1被触发 
执行before_first_request扩展
from flask import Flask,render_template
from flask import signals
app = Flask(__name__, static_url_path='/yy')

@signals.request_started.connect
def f3(arg):
    print('request_started信号被触发',arg)

@app.route('/')
def index():
    return render_template('img.html')

@app.route('/order')
def order():
    return render_template('img.html')

if __name__ == '__main__':
    app.run()
* Serving Flask app '__main__'
 * Debug mode: off

WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
 * Running on http://127.0.0.1:5000
Press CTRL+C to quit
127.0.0.1 - - [20/May/2024 11:57:32] "GET / HTTP/1.1" 200 -
127.0.0.1 - - [20/May/2024 11:57:33] "GET /yy/img/haha.png HTTP/1.1" 304 -

request_started信号被触发 
request_started信号被触发 
url_value_processor

在请求之前被触发

from flask import Flask,render_template,g
from flask import signals
app = Flask(__name__, static_url_path='/yy')

@app.url_value_preprocessor
def f5(endpoint,args):
    print('f5')

@app.route('/')
def index():
    return render_template('img.html')

@app.route('/order')
def order():
    return render_template('img.html')

if __name__ == '__main__':
    app.run()
* Serving Flask app '__main__'
 * Debug mode: off

WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
 * Running on http://127.0.0.1:5000
Press CTRL+C to quit
127.0.0.1 - - [20/May/2024 11:59:28] "GET / HTTP/1.1" 200 -
127.0.0.1 - - [20/May/2024 11:59:28] "GET /yy/img/haha.png HTTP/1.1" 304 -

request_started信号被触发 
f5
request_started信号被触发 
f5
before_reuqest
from flask import Flask,render_template,g
from flask import signals
app = Flask(__name__, static_url_path='/yy')

@app.before_request
def f6():
    g.xx = 123
    print('f6')

@app.route('/')
def index():
    print('index')
    return render_template('img.html')

if __name__ == '__main__':
    app.run()
* Serving Flask app '__main__'
 * Debug mode: off

WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
 * Running on http://127.0.0.1:5000
Press CTRL+C to quit
127.0.0.1 - - [20/May/2024 14:49:58] "GET / HTTP/1.1" 200 -
127.0.0.1 - - [20/May/2024 14:49:58] "GET /yy/img/haha.png HTTP/1.1" 304 -

f6
index
f6
视图函数

before_render_template / rendered_template

from flask import Flask,render_template,g
from flask import signals
app = Flask(__name__, static_url_path='/yy')

@signals.before_render_template.connect
def f7(app, template, context):
    print('before_render_template f7 被触发')

@signals.template_rendered.connect
def f8(app, template, context):
    print('template_rendered f8 被触发')

@app.route('/')
def index():
    print('index')
    return render_template('img.html')

if __name__ == '__main__':
    app.run()
* Serving Flask app '__main__'
 * Debug mode: off

WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
 * Running on http://127.0.0.1:5000
Press CTRL+C to quit
127.0.0.1 - - [20/May/2024 15:01:57] "GET / HTTP/1.1" 200 -
127.0.0.1 - - [20/May/2024 15:01:57] "GET /yy/img/haha.png HTTP/1.1" 304 -

index
before_render_template f7 被触发
template_rendered f8 被触发
after_request
from flask import Flask,render_template,g
from flask import signals
app = Flask(__name__, static_url_path='/yy')

@app.after_request
def f9(response):
    print('after_request f9 被触发')
    return response

@app.route('/')
def index():
    print('index')
    return render_template('img.html')

@app.route('/order')
def order():
    print('order')
    return render_template('img.html')

if __name__ == '__main__':
    app.run()
* Serving Flask app '__main__'
 * Debug mode: off

WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
 * Running on http://127.0.0.1:5000
Press CTRL+C to quit
127.0.0.1 - - [20/May/2024 15:07:55] "GET / HTTP/1.1" 200 -
127.0.0.1 - - [20/May/2024 15:07:55] "GET /yy/img/haha.png HTTP/1.1" 304 -

index
after_request f9 被触发
after_request f9 被触发
request_finished
from flask import Flask,render_template,g
from flask import signals
app = Flask(__name__, static_url_path='/yy')

@signals.request_finished.connect
def f10(app,response):
    print('request_finished f10 被触发')

@app.route('/')
def index():
    print('index')
    return render_template('img.html')

@app.route('/order')
def order():
    print('order')
    return render_template('img.html')

if __name__ == '__main__':
    app.run()
* Serving Flask app '__main__'
 * Debug mode: off

WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
 * Running on http://127.0.0.1:5000
Press CTRL+C to quit
127.0.0.1 - - [20/May/2024 15:09:16] "GET / HTTP/1.1" 200 -
127.0.0.1 - - [20/May/2024 15:09:16] "GET /yy/img/haha.png HTTP/1.1" 304 -

index
request_finished f10 被触发
request_finished f10 被触发
got_request_exception
from flask import Flask,render_template,g
from flask import signals
app = Flask(__name__, static_url_path='/yy')

@app.before_first_request
def test():
    int('asdf')

@signals.got_request_exception.connect
def f11(app,exception):
    print('got_request_exception f11 被触发')

@app.route('/')
def index():
    print('index')
    return render_template('img.html')

@app.route('/order')
def order():
    print('order')
    return render_template('img.html')

if __name__ == '__main__':
    app.run()
teardown_request
from flask import Flask,render_template,g
from flask import signals
app = Flask(__name__, static_url_path='/yy')

@app.teardown_request
def f12(exc):
    print('teardown_request f12 被触发')

@app.route('/')
def index():
    print('index')
    return render_template('img.html')

@app.route('/order')
def order():
    print('order')
    return render_template('img.html')

if __name__ == '__main__':
    app.run()
* Serving Flask app '__main__'
 * Debug mode: off

WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
 * Running on http://127.0.0.1:5000
Press CTRL+C to quit
127.0.0.1 - - [20/May/2024 15:12:13] "GET / HTTP/1.1" 200 -
127.0.0.1 - - [20/May/2024 15:12:14] "GET /yy/img/haha.png HTTP/1.1" 304 -

index
teardown_request f12 被触发
teardown_request f12 被触发
request_tearing_down
from flask import Flask,render_template,g
from flask import signals
app = Flask(__name__, static_url_path='/yy')

@signals.request_tearing_down.connect
def f13(app,exc):
    print('request_tearing_down f13 被触发')

@app.route('/')
def index():
    print('index')
    return render_template('img.html')

@app.route('/order')
def order():
    print('order')
    return render_template('img.html')

if __name__ == '__main__':
    app.run()
* Serving Flask app '__main__'
 * Debug mode: off

WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
 * Running on http://127.0.0.1:5000
Press CTRL+C to quit
127.0.0.1 - - [20/May/2024 15:13:16] "GET / HTTP/1.1" 200 -
127.0.0.1 - - [20/May/2024 15:13:16] "GET /yy/img/haha.png HTTP/1.1" 304 -

index
request_tearing_down f13 被触发
request_tearing_down f13 被触发
appcontext_popped
from flask import Flask,render_template,g
from flask import signals
app = Flask(__name__, static_url_path='/yy')

@signals.appcontext_popped.connect
def f14(app):
    print('appcontext_popped f14 被触发')

@app.route('/')
def index():
    print('index')
    return render_template('img.html')

@app.route('/order')
def order():
    print('order')
    return render_template('img.html')

if __name__ == '__main__':
    app.run()
* Serving Flask app '__main__'
 * Debug mode: off

WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
 * Running on http://127.0.0.1:5000
Press CTRL+C to quit
127.0.0.1 - - [20/May/2024 15:14:10] "GET / HTTP/1.1" 200 -
127.0.0.1 - - [20/May/2024 15:14:10] "GET /yy/img/haha.png HTTP/1.1" 304 -

index
appcontext_popped f14 被触发
appcontext_popped f14 被触发

总结

总结:关于flask内部共有14+个扩展点用于我们对flask框架内部进行定制,其中有:9个是信号。

template_rendered = _signals.signal("template-rendered")
before_render_template = _signals.signal("before-render-template")
request_started = _signals.signal("request-started")
request_finished = _signals.signal("request-finished")
request_tearing_down = _signals.signal("request-tearing-down")
got_request_exception = _signals.signal("got-request-exception")
appcontext_tearing_down = _signals.signal("appcontext-tearing-down")
appcontext_pushed = _signals.signal("appcontext-pushed")
appcontext_popped = _signals.signal("appcontext-popped")

message_flashed = _signals.signal("message-flashed")

扩展:flash

flash存值之后只能取一次

from flask import Flask,render_template,flash,get_flashed_messages,session
from flask import signals
app = Flask(__name__, static_url_path='/yy')
app.secret_key = 'iuknsoiuwknlskjdf'

@app.route('/')
def index():
    # flash('123')
    session['k1'] = 123
    return render_template('img.html')

@app.route('/order')
def order():
    # messages = get_flashed_messages()
    # print(messages)
    val = session['k1']
    del session['k1']
    print('session k1:', val)
    return render_template('img.html')

if __name__ == '__main__':
    app.run()

flask-script

flask的组件,用于运行flask程序。

安装: pip3 install flask-script

from demo import create_app
from flask_script import Manager

app = create_app()
manager = Manager(app)

@manager.command
def custom(arg):
    """
    自定义命令
    python manage.py custom 123
    :param arg:
    :return:
    """
    print(arg)

@manager.option('-n', '--name', dest='name')
@manager.option('-u', '--url', dest='url')
def cmd(name, url):
    """
    自定义命令
    执行: python manage.py  cmd -n waws -u http://www.baidu.com
    :param name:
    :param url:
    :return:
    """
    print(name, url)

if __name__ == '__main__':
    manager.run()
python manage.py  cmd -n waws -u http://www.baidu.com
python manage.py custom 123
其他

结合:flask-migrate / flask-sqlalchemy

python manage.py migrate

蓝图

分功能蓝图(项目大)
- waws_project(项目)
    - waws_project(蓝图)
        - user(用户功能)
            - static
            - templates
                - add_user.html 
            - views
                - add_user.py
                - remove_user.py
            - __init__.py
        - power(权限功能)
            - static
            - templates
            - views
                - add_power.py
                - remove_power.py
            - __init__.py
        - ......
        - __init__.py
    - config
        - settings.py
    - manage.py
# user/__init__.py文件
from flask import Blueprint,render_template

# 蓝图中视图函数render_template默认会去蓝图根目录找模板文件,没有在去功能蓝图的templates下查找
user = Blueprint('user',__name__,template_folder='templates')

# 因为是从manage.py启动的文件,所以在注册蓝图的时候可以走到当前文件,但是无法和视图函数进行关联,所以需要在这个地方引入才行
from .view import add_user

# waws_project/__init__.py文件
from flask import Flask

def create_app():
    app = Flask(__name__)
    app.config.from_object('config.settings')

    from .user import user
    from .power import power

    app.register_blueprint(user)
    app.register_blueprint(power)

    return app

# view/add_user.py
from .. import user
from flask import render_template

@user.route("/add_user")
def add_user():
    return render_template("add_user.html")
分结构蓝图(项目中、小)
- waws_project(项目)
    - waws_project(蓝图)
        - static
        - templates
            - add_user.html 
        - views
            - add_user.py
            - remove_user.py
        - __init__.py
    - config
        - settings.py
    - manage.py