【问题标题】:In Flask, is it there a way to run some code before every view?在 Flask 中,有没有办法在每个视图之前运行一些代码?
【发布时间】:2019-12-31 00:59:15
【问题描述】:

我想在每个视图的代码执行之前使用 get_flashed_messages() 清理会话闪存。那是因为 flash 在 session 中是持久的,这是非常不幸的(如果 flashed 消息没有在身份验证过程中打印,例如,它们会在使用布局的第一页中一次全部打印出来)。

所以,我想在应用程序中的每个视图之前运行代码来清理会话闪烁的消息。

诸如 before_request 或 before_app_request 之类的函数不会正确执行,因为它们在请求期间会执行很多次(它们会针对正在上传的每个模板或静态文件执行),这会擦除视图代码中闪烁的消息(我只想在当前视图开始运行之前从其他视图中删除持久化的消息)。

简单地说,我希望一些代码在调用每个视图函数之前运行一次,并且只运行一次。

这在 Flask 中可行吗?

【问题讨论】:

    标签: python flask


    【解决方案1】:

    来源:https://flask.palletsprojects.com/en/1.1.x/templating/

    为了将新变量自动注入到模板的上下文中,Flask 中存在上下文处理器。上下文处理器在模板渲染之前运行,并且能够将新值注入到模板上下文中。上下文处理器是一个返回字典的函数。对于应用程序中的所有模板,此字典的键和值随后与模板上下文合并:

    @app.context_processor
    def inject_user():
        return dict(user=g.user)
    

    上面的上下文处理器使一个名为 user 的变量在模板中可用,其值为 g.user。这个例子不是很有趣,因为 g 无论如何都可以在模板中使用,但它给出了它是如何工作的概念。

    变量不限于值;上下文处理器还可以使函数对模板可用(因为 Python 允许传递函数):

    @app.context_processor
    def utility_processor():
        def format_price(amount, currency=u'€'):
            return u'{0:.2f}{1}'.format(amount, currency)
        return dict(format_price=format_price)
    

    上面的上下文处理器使 format_price 函数可用于所有模板:

    {{ format_price(0.33) }}
    

    【讨论】:

    • 这恰好对我用 before_request 做的另一件事很有用。上下文处理器似乎更适合该用例。
    【解决方案2】:

    如果在蓝图上使用before_request 挂钩?这应该只会影响蓝图视图。

    before_request(f)
    像 Flask.before_request() 但用于蓝图。此函数仅在>由该蓝图的函数处理的每个请求之前执行。

    参考:https://flask.palletsprojects.com/en/1.1.x/api/?highlight=before_request#flask.Blueprint.before_request

    更新

    我尝试了一些代码如下:

    app.py

    from flask import Flask
    from app.ext import db, login_manager
    
    def create_app():
        app = Flask(__name__)
        app.config.from_object(config)
        db.init_app(app)
        login_manager.init_app(app)
        # blueprints
        register_blueprints('app.views', app)
        return app
    

    views/myview.py

    from flask import (
        Blueprint, render_template,
        flash, get_flashed_messages
    )
    from flask_login import login_required
    
    bp = Blueprint('myview', __name__, url_prefix='/myview')
    
    
    @bp.before_request
    def before_func():
        print(get_flashed_messages())
        print('---------------')
    
    
    @bp.route('/index', methods=['GET'])
    @login_required
    def index():
        flash('Now in index')
        return render_template('index.html')
    
    
    @bp.route('/home', methods=['GET'])
    @login_required
    def home():
        flash('Now in home')
        return render_template('home.html')
    

    当我运行代码时。 myview 中的每个请求只执行一次 before_func。那么,这是你想要的吗?

    【讨论】:

    • 我试过了。尽管如此,它还是被多次调用。我不知道为什么,但是在返回视图之前,flask 会向同一个蓝图发出很多请求。我认为这至少部分是因为flask_login。因此,我需要为每个视图运行一次且仅运行一次的东西,而不是请求。
    【解决方案3】:

    如果是常用功能,可以使用wraps from functools 编写装饰器。确保在 app.route 装饰器下方编写装饰器。

    【讨论】:

    • 嗨!好吧,那会奏效...但是我必须在平台中的每个视图上方编写装饰器。我正在寻找一个更像 before_request 的钩子。
    猜你喜欢
    • 2022-01-10
    • 2018-05-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-07-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多