Flask1.0.2系列(十三) 应用程序上下文

英文原文地址:http://flask.pocoo.org/docs/1.0/appcontext/

若有翻译错误或者不尽人意之处,请指出,谢谢~


        应用程序上下文在一个请求、CLI命令或者其他活动期间保持追踪应用程序级别数据。相较于为每个方法传递应用程序对象,我们可以直接访问current_appg两个代理。


1. 上下文的目的

        Flask应用程序对象拥有很多属性,比如config,这些属性在视图和CLI 命令(CLI命令后面会讲解)中访问是非常有用的。然而,在项目的模块中导入app对象是非常容易引起循环导入的问题。当使用应用程序工厂模式(app factory pattern,后面会专门讲解)或者编写可重用的蓝图(后面会讲解)亦或是扩展(后面会讲解)时,根本不会导入一个app实例。

        Flask使用应用程序上下文(application context)来解决这些问题。相比于直接引用一个app实例,你应该使用current_app代理,这个代理指向了正在处理当前活动的应用程序。

        在处理一个请求时,Flask自动地推送(pushes)了一个应用程序上下文。视图方法,错误处理程序,以及其他运行在一个请求期间的方法,都可以访问current_app代理对象。

        在运行Flask.cli注册的(使用@app.cli.command()装饰器)CLI命令时,Flask也自动地推送了一个应用程序上下文。


2. 上限文的生命周期

        应用程序上下文在必要时会被创建和被销毁。当一个Flask应用程序开始处理一个请求时,它推送了一个应用程序上下文和一个请求上下文(request context,下一章节的内容)。当这个请求结束时,它会取出这个请求上下文,然后取出这个应用程序上下文。一般而言,一个应用程序上下文与一个请求有着同样的生命周期。


3. 手动推送一个上下文

        如果你在一个应用程序上下文之外,尝试访问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命令中。


4. 存储数据

        在一个请求或者CLI命令期间,应用程序上下文是一个不错的存储常用数据的地方。Flask提供g对象来实现这个目标。这是一个简单的命令空间对象,它与一个应用程序上下文的生命周期一致。

        注意:

        g的名字表示“global”,但它引用的数据是全局的,前提必须是在一个上下文中。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():
    db = g.pop('db', None)

    if db is not None:
        db.close()

        在一个请求期间,任何调用get_db()方法的地方都会返回同样的连接对象,并且它会在这个请求结束的时候自动地关闭。

        你可以使用LocalProxy来为get_db()中生成一个新的本地上下文:

from werkzeug.local import LocalProxy


db = LocalProxy(get_db)

        访问db时内部会调用get_db方法,这与current_app工作方式相同。

        如果你正在编写一个扩展,应该为用户代码保留g。你可能在上下文本身存储内部数据,但是确保要使用一个唯一的名字。使用_app_ctx_stack.top可以访问当前上下文。后续Flask扩展开发可以看到更多相关信息。


5. 事件和信号

        当应用程序上下文被取出时,应用程序会所有调用被teardown_appcontext()注册过的方法。

        如果signals_available的值是true,那么下面的信号都会被发送:appcontext_pushedappcontext_tearing_downappcontext_popped

猜你喜欢

转载自blog.csdn.net/ReganDu/article/details/80199061
今日推荐