什么时候应该使用Flask.g?

Yan*_*nin 157 python flask

看到的是g将从请求上下文移动到瓶0.10的应用程序上下文,这让我困惑的用途的g.

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

  • g 生活在请求上下文中,即在请求开始时重新创建,并且可用直到它结束
  • g用作"请求黑板",我可以在请求的持续时间内放置相关的东西(即,在请求开始时设置一个标志并在最后处理它,可能来自before_request/ after_requestpair)
  • 除了保持请求级别状态之外,g可以并且应该用于资源管理,即保存数据库连接等.

Flask 0.10中哪些句子不再适用?有人能指点我讨论改变原因的资源吗?我应该在Flask 0.10中使用什么作为"请求黑板" - 我应该创建自己的应用程序/扩展特定的线程本地代理并将其推送到上下文堆栈before_request吗?如果我的应用程序存在很长时间(不像请求),那么资源管理在应用程序上下文中的重点是什么?因此资源永远不会被释放?

the*_*man 108

高级瓶模式,如由马库斯联系,解释了一些变化到g0.10:

  • g 现在生活在应用程序环境中.
  • 每个请求都会推送一个新的应用程序上下文,擦除旧的应用程序上下文,因此g仍然可以用来为每个请求设置标志而无需更改代码.
  • 调用 teardown_request会弹出应用程序上下文.(阿明的介绍解释说,这是因为事情像创建数据库连接的任务,其设置为请求的环境,而不应被内部处理before_requestafter_request)

  • 你指的是[推送`app.app_context()`](https://github.com/pallets/flask/blob/master/flask/ctx.py#L317)?如果是这样,应该注意 [`app_context()`](https://github.com/pallets/flask/blob/master/flask/app.py#L2080-L2093) 每次调用都会实例化一个新的应用程序上下文——它从不重用上下文。 (2认同)
  • 噢,抱歉,我看错了!在生产环境中,每个线程(或 greenlet)仅处理一个请求。仅推送一个“RequestContext”,因此仅推送一个“AppContext”。但是如果[调试模式打开并且请求失败,Flask 会保存上下文](https://git.io/v7WAt),因此[它可以与调试器一起使用](https://git.io/v7WAI) 。`None` 被附加到 `_app_ctx_stack` 中,因此当请求被拆除时,它知道还不能弹出 `AppContext`。测试客户端也会发生同样的情况,它保留上下文,因此可以对其进行检查。 (2认同)

Jaz*_*aza 69

作为本主题信息的附录:我对行为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))
Run Code Online (Sandbox Code Playgroud)

这是它给出的输出:

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
Run Code Online (Sandbox Code Playgroud)

正如Y4Kman所说,"每个请求都会推动一个新的应用程序上下文".而随着烧瓶文档说,应用程序上下文"将不被请求之间共享".现在,没有明确说明的内容(虽然我猜这是从这些语句中隐含的),以及我的测试清楚显示的是,你应该永远不要显式创建嵌套在一个应用程序上下文中的多个请求上下文,因为flask.g(和co)没有'它具有任何魔力,它在上下文的两个不同"级别"中起作用,不同的状态在应用程序和请求级别独立存在.

实际情况是"应用程序上下文"可能是一个误导性的名称,因为它app.app_context() 一个每请求上下文,与"请求上下文"完全相同.将其视为"请求上下文精简版",仅在需要某些通常需要请求上下文的变量但不需要访问任何请求对象的情况下才需要(例如,在运行批处理数据库操作时) shell脚本).如果您尝试将应用程序上下文扩展为包含多个请求上下文,那么您就会遇到麻烦.所以,而不是我上面的测试,你应该用Flask的上下文编写这样的代码:

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))
Run Code Online (Sandbox Code Playgroud)

这将给出预期的结果:

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
Run Code Online (Sandbox Code Playgroud)

  • 由于最后一段而受到支持,flask的上下文一开始很难理解。从名称中,您会感觉到请求上下文是针对每个请求的,并且应用程序上下文即使在请求之后也存在,或者不受其生存期的影响。 (3认同)