在Flask 0.10中,我看到g将从请求上下文移动到应用上下文,这让我对g的预期用途感到困惑。

我的理解(对于Flask 0.9)是:

G存在于请求上下文中,也就是说,在请求开始时重新创建,直到它结束都可用 g打算用作“请求黑板”,在那里我可以放一些与请求持续时间相关的东西(即,在请求的开始设置一个标志,并在结束时处理它,可能来自before_request/after_request对) 除了保存请求级状态外,g还可以而且应该用于资源管理,即保存数据库连接等。

下面哪个句子在Flask 0.10中不再正确了?有人能给我指出一个资源来讨论这个变化的原因吗?我应该在Flask 0.10中使用什么作为“请求黑板”——我应该创建自己的应用/扩展特定的线程本地代理并将其推送到上下文堆栈before_request吗?如果我的应用程序存在很长一段时间(不像请求),因此资源永远不会被释放,那么在应用程序上下文中进行资源管理的意义是什么?


高级Flask Patterns,如Markus所链接的,解释了0.10中g的一些变化:

G现在存在于应用程序上下文中。 每个请求都会推送一个新的应用程序上下文,清除旧的上下文,所以g仍然可以用来为每个请求设置标志,而无需更改代码。 在调用teardown_request之后弹出应用程序上下文。(Armin的演示解释了这是因为像创建DB连接这样的事情是为请求设置环境的任务,不应该在before_request和after_request内部处理)


作为这条线索中的信息的补充:我对flask的行为有点困惑。G也是,但一些快速测试帮助我澄清了它。以下是我尝试过的方法:

from flask import Flask, g
app = Flask(__name__)

with app.app_context():
    print('in app context, before first request context')
    print('setting g.foo to abc')
    g.foo = 'abc'
    print('g.foo should be abc, is: {0}'.format(g.foo))

    with app.test_request_context():
        print('in first request context')
        print('g.foo should be abc, is: {0}'.format(g.foo))
        print('setting g.foo to xyz')
        g.foo = 'xyz'
        print('g.foo should be xyz, is: {0}'.format(g.foo))

    print('in app context, after first request context')
    print('g.foo should be abc, is: {0}'.format(g.foo))

    with app.test_request_context():
        print('in second request context')
        print('g.foo should be abc, is: {0}'.format(g.foo))
        print('setting g.foo to pqr')
        g.foo = 'pqr'
        print('g.foo should be pqr, is: {0}'.format(g.foo))

    print('in app context, after second request context')
    print('g.foo should be abc, is: {0}'.format(g.foo))

这是它给出的输出:

in app context, before first request context
setting g.foo to abc
g.foo should be abc, is: abc  

in first request context
g.foo should be abc, is: abc
setting g.foo to xyz
g.foo should be xyz, is: xyz  

in app context, after first request context
g.foo should be abc, is: xyz  

in second request context
g.foo should be abc, is: xyz
setting g.foo to pqr
g.foo should be pqr, is: pqr  

in app context, after second request context
g.foo should be abc, is: pqr

As theY4Kman said above, "Every request pushes a new application context". And as the Flask docs say, the application context "will not be shared between requests". Now, what hasn't been explicitly stated (although I guess it's implied from these statements), and what my testing clearly shows, is that you should never explicitly create multiple request contexts nested inside one application context, because flask.g (and co) doesn't have any magic whereby it functions in the two different "levels" of context, with different states existing independently at the application and request levels.

The reality is that "application context" is potentially quite a misleading name, because app.app_context() is a per-request context, exactly the same as the "request context". Think of it as a "request context lite", only required in the case where you need some of the variables that normally require a request context, but you don't need access to any request object (e.g. when running batch DB operations in a shell script). If you try and extend the application context to encompass more than one request context, you're asking for trouble. So, rather than my test above, you should instead write code like this with Flask's contexts:

from flask import Flask, g
app = Flask(__name__)

with app.app_context():
    print('in app context, before first request context')
    print('setting g.foo to abc')
    g.foo = 'abc'
    print('g.foo should be abc, is: {0}'.format(g.foo))

with app.test_request_context():
    print('in first request context')
    print('g.foo should be None, is: {0}'.format(g.get('foo')))
    print('setting g.foo to xyz')
    g.foo = 'xyz'
    print('g.foo should be xyz, is: {0}'.format(g.foo))

with app.test_request_context():
    print('in second request context')
    print('g.foo should be None, is: {0}'.format(g.get('foo')))
    print('setting g.foo to pqr')
    g.foo = 'pqr'
    print('g.foo should be pqr, is: {0}'.format(g.foo))

这将给出预期的结果:

in app context, before first request context
setting g.foo to abc
g.foo should be abc, is: abc  

in first request context
g.foo should be None, is: None
setting g.foo to xyz
g.foo should be xyz, is: xyz  

in second request context
g.foo should be None, is: None
setting g.foo to pqr
g.foo should be pqr, is: pqr