应用情境

应用情境在请求, CLI 命令或其他活动期间跟踪应用级数据。不是将应用程序传递给每个函数,而是代之以访问 current_appg 代理。

这与 请求情境 类似,它在请求期间跟踪请求级数据。推送请求情境时会推送相应的应用情境。

情境的目的

Flask 应用对象具有诸如 config 之类的属性,这些属性对于在视图和 CLI commands 中访问很有用。但是,在项目中的模块内导入 app 实例容易导致循环导入问题。当使用应用程序工厂方案 或编写可重用的blueprintsextensions 时,根本不会有应用程序实例导入。

  • Flask 通过 应用情境 解决了这个问题。不是直接引用一个 app ,而是使用
  • current_app 代理,该代理指向处理当前活动的应用。

处理请求时, Flask 自动 推送 应用情境。在请求期间运行的视图函数、错误处理器和其他函数将有权访问 current_app

运行使用 @app.cli.command() 注册到 Flask.cli 的 CLI 命令时,Flask 还会自动推送应用情境。

情境的生命周期

应用情境根据需要创建和销毁。当 Flask 应用开始处理请求时,它会推送应用情境和 请求情境 。当请求结束时,它会在请求情境中弹出,然后在应用情境中弹出。通常,应用情境将具有与请求相同的生命周期。

请参阅 请求情境 以获取有关情境如何工作以及请求的完整生命周期的更多信息。

手动推送情境

如果您尝试在应用情境之外访问 current_app ,或其他任何使用它的东西,则会看到以下错误消息:

  1. RuntimeError: Working outside of application context.
  2. 这通常意味着您试图使用功能需要以某种方式与当前的应用程序对象进行交互。
  3. 要解决这个问题,请使用 app.app_context()设置应用情境。

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

  1. def create_app():
  2. app = Flask(__name__)
  3. with app.app_context():
  4. init_db()
  5. return app

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

存储数据

应用情境是在请求或 CLI 命令期间存储公共数据的好地方。Flask 为此提供了g 对象 。它是一个简单的命名空间对象,与应用情境具有相同的生命周期。

Note

g 表示“全局”的意思,但是指的是数据在 情境 之中是全局的。 g中的数据在情境结束后丢失,因此它不是在请求之间存储数据的恰当位置。使用session 或数据库跨请求存储数据。

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

  • get_X() 创建资源 X (如果它不存在),将其缓存为 g.X

  • teardown_X() 关闭或以其他方式解除分配资源(如果存在)。它被注册为teardown_appcontext() 处理器。

例如,您可以使用以下方案管理数据库连接:

  1. from flask import g
  2. def get_db():
  3. if 'db' not in g:
  4. g.db = connect_to_database()
  5. return g.db
  6. @app.teardown_appcontext
  7. def teardown_db():
  8. db = g.pop('db', None)
  9. if db is not None:
  10. db.close()

在一个请求中,每次调用 get_db() 会返回同一个连接,并且会在请求结束时自动关闭连接。

你可以使用 LocalProxy 基于 get_db()生成一个新的本地情境:

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

访问 db 就会内部调用 get_db ,与 current_app 的工作方式相同。


如果你正在编写扩展, g 应该保留给用户。你可以将内部数据存储在情境本身中,但一定要使用足够唯一的名称。当前上下文使用_app_ctx_stack.top 访问。 欲了解更多信息,请参阅Flask 扩展开发

事件和信号

当应用情境被弹出时,应用将调用使用 teardown_appcontext()注册的函数。

如果 signals_available 为真,则发送以下信号:appcontext_pushedappcontext_tearing_downappcontext_popped