应用程序上下文

应用程序上下文在请求、CLI 命令或其他活动期间跟踪应用程序级数据。应用程序上下文不会传递给每个函数,而是访问 current_appg 代理。

这类似于 请求上下文,它在请求期间跟踪请求级数据。当请求上下文被推送时,将推送相应的应用程序上下文。

上下文的用途

Flask 应用程序对象具有属性,例如 config,在视图和 CLI 命令 中访问这些属性非常有用。但是,在项目的模块中导入 app 实例很容易出现循环导入问题。使用 应用程序工厂模式 或编写可重用的 蓝图扩展 时,根本不会有 app 实例可供导入。

Flask 通过应用程序上下文解决了此问题。您不必直接引用 app,而是使用 current_app 代理,该代理指向处理当前活动的应用程序。

Flask 在处理请求时会自动推送应用程序上下文。视图函数、错误处理程序以及在请求期间运行的其他函数将能够访问 current_app

使用 @app.cli.command()Flask.cli 中注册的 CLI 命令运行时,Flask 还将自动推送一个应用上下文。

上下文的生命周期

应用程序上下文根据需要创建和销毁。当 Flask 应用程序开始处理请求时,它将推送一个应用程序上下文和一个 请求上下文。当请求结束时,它将弹出请求上下文,然后弹出应用程序上下文。通常,应用程序上下文的生命周期与请求相同。

有关上下文的工作方式和请求的完整生命周期的更多信息,请参阅 请求上下文

手动推送上下文

如果你尝试在应用程序上下文之外访问 current_app 或使用它的任何内容,你将收到此错误消息

RuntimeError: Working outside of application context.

This typically means that you attempted to use functionality that
needed to interface with the current application object in some way.
To solve this, set up an application context with app.app_context().

如果你在配置应用程序时看到该错误,例如在初始化扩展时,你可以手动推送一个上下文,因为你可以直接访问 app。在 with 块中使用 app_context(),在该块中运行的所有内容都可以访问 current_app

def create_app():
    app = Flask(__name__)

    with app.app_context():
        init_db()

    return app

如果你在与配置应用程序无关的代码中的其他位置看到该错误,则很可能表示你应该将该代码移到视图函数或 CLI 命令中。

存储数据

应用程序上下文是请求或 CLI 命令期间存储常见数据的好地方。Flask 提供 g 对象 来实现此目的。它是一个简单的命名空间对象,具有与应用程序上下文相同的生命周期。

注意

g 名称代表“全局”,但这是指在 上下文中 中的数据是全局的。g 上的数据在上下文结束后丢失,它不是在请求之间存储数据的合适位置。使用 session 或数据库在请求之间存储数据。

一个 g 的常见用法是在请求期间管理资源。

  1. get_X() 在资源 X 不存在时创建该资源,并将其缓存为 g.X

  2. teardown_X() 在资源存在时关闭或以其他方式释放该资源。它被注册为 teardown_appcontext() 处理程序。

例如,你可以使用此模式管理数据库连接

from flask import g

def get_db():
    if 'db' not in g:
        g.db = connect_to_database()

    return g.db

@app.teardown_appcontext
def teardown_db(exception):
    db = g.pop('db', None)

    if db is not None:
        db.close()

在请求期间,对 get_db() 的每次调用都将返回相同的连接,并且它将在请求结束时自动关闭。

你可以使用 LocalProxyget_db() 创建一个新的上下文本地

from werkzeug.local import LocalProxy
db = LocalProxy(get_db)

访问 db 将在内部调用 get_db,就像 current_app 的工作方式一样。

事件和信号

当应用程序上下文弹出时,应用程序将调用使用 teardown_appcontext() 注册的函数。

发送以下信号: appcontext_pushedappcontext_tearing_downappcontext_popped