gpt4 book ai didi

python - Flask 的上下文堆栈的目的是什么?

转载 作者:行者123 更新时间:2023-12-01 18:51:33 29 4
gpt4 key购买 nike

我已经使用请求/应用程序上下文有一段时间了,但没有完全理解它是如何工作的,或者为什么它是这样设计的。当涉及到请求或应用程序上下文时,“堆栈”的目的是什么?这是两个独立的堆栈,还是它们都属于一个堆栈?请求上下文是推送到堆栈上,还是堆栈本身?我可以在彼此之上推送/弹出多个上下文吗?如果是这样,我为什么要这样做?

对于所有问题,我很抱歉,但在阅读了 Request Context 和 Application Context 的文档后,我仍然感到困惑。

最佳答案

多个应用程序

应用程序上下文(及其目的)确实令人困惑,直到您意识到 Flask 可以有多个应用程序。想象一下你想让一个 WSGI Python 解释器运行多个 Flask 应用程序的情况。我们在这里不是在谈论蓝图,而是在谈论完全不同的 Flask 应用程序。

您可以将其设置为类似于 Flask documentation section on "Application Dispatching"例子:

from werkzeug.wsgi import DispatcherMiddleware
from frontend_app import application as frontend
from backend_app import application as backend

application = DispatcherMiddleware(frontend, {
'/backend': backend
})

请注意,“前端”和“后端”创建了两个完全不同的 Flask 应用程序。换句话说, Flask(...)应用程序构造函数被调用了两次,创建了一个 Flask 应用程序的两个实例。

上下文

当您使用 Flask 时,您通常最终会使用全局变量来访问各种功能。例如,您可能有读取...
from flask import request

然后,在查看期间,您可能会使用 request访问当前请求的信息。显然, request不是普通的全局变量;实际上,它是一个 context local值(value)。换句话说,幕后有一些魔法说“当我调用 request.path 时,从 CURRENT 请求的 path 对象中获取 request 属性。”对于 request.path,两个不同的请求会产生不同的结果。 .

事实上,即使你用多个线程运行 Flask,Flask 也足够聪明,可以保持请求对象的隔离。这样一来,两个线程就可以同时调用 request.path,每个线程处理不同的请求。并为他们各自的请求获取正确的信息。

放在一起

所以我们已经看到 Flask 可以在同一个解释器中处理多个应用程序,而且由于 Flask 允许您使用“上下文本地”全局变量的方式,必须有某种机制来确定“当前”请求是什么(为了做诸如 request.path 之类的事情)。

将这些想法放在一起,Flask 必须有某种方法来确定“当前”应用程序是什么也应该是有意义的!

您可能还有类似于以下内容的代码:
from flask import url_for

喜欢我们的 request例如, url_for函数具有依赖于当前环境的逻辑。然而,在这种情况下,很明显逻辑在很大程度上取决于哪个应用程序被视为“当前”应用程序。在上面显示的前端/后端示例中,“前端”和“后端”应用程序都可以有一个“/登录”路由,因此 url_for('/login')应该返回不同的内容,具体取决于 View 是在处理前端应用程序还是后端应用程序的请求。

要回答您的问题...

What is the purpose of the "stack" when it comes to the request or application context?



从请求上下文文档:

Because the request context is internally maintained as a stack you can push and pop multiple times. This is very handy to implement things like internal redirects.



换句话说,即使您通常在这些“当前”请求或“当前”应用程序堆栈上有 0 或 1 个项目,您也可能有更多。

给出的示例是您的请求将返回“内部重定向”的结果。假设用户请求 A,但您想返回给用户 B。在大多数情况下,您向用户发出重定向,并将用户指向资源 B,这意味着用户将运行第二个请求来获取 B。A稍微不同的处理方式是进行内部重定向,这意味着在处理 A 时,Flask 将向自己发出一个新的资源 B 请求,并将第二个请求的结果用作用户原始请求的结果。

Are these two separate stacks, or are they both part of one stack?



他们是 two separate stacks .然而,这是一个实现细节。更重要的不是有一个堆栈,而是您可以随时获取“当前”应用程序或请求(堆栈顶部)的事实。

Is the request context pushed onto a stack, or is it a stack itself?



“请求上下文”是“请求上下文堆栈”的一项。与“应用上下文”和“应用上下文堆栈”类似。

Am I able to push/pop multiple contexts on top of eachother? If so, why would I want to do that?



在 Flask 应用程序中,您通常不会这样做。您可能想要的一个示例是内部重定向(如上所述)。然而,即使在这种情况下,您最终也可能会让 Flask 处理一个新请求,因此 Flask 会为您完成所有推送/弹出操作。

但是,在某些情况下,您希望自己操作堆栈。

在请求之外运行代码

人们遇到的一个典型问题是他们使用 Flask-SQLAlchemy 扩展来设置 SQL 数据库和模型定义,使用如下所示的代码...
app = Flask(__name__)
db = SQLAlchemy() # Initialize the Flask-SQLAlchemy extension object
db.init_app(app)

然后他们使用 appdb应从 shell 运行的脚本中的值。例如,“setup_tables.py”脚本...
from myapp import app, db

# Set up models
db.create_all()

在这种情况下,Flask-SQLAlchemy 扩展知道 app申请,但在 create_all() 期间它会抛出一个错误,提示没有应用程序上下文。这个错误是有道理的;你从来没有告诉 Flask 在运行 create_all 时它应该处理什么应用程序方法。

您可能想知道为什么您最终不需要这个 with app.app_context()在 View 中运行类似函数时调用。原因是 Flask 在处理实际 Web 请求时已经为您处理了应用程序上下文的管理。问题实际上只出现在这些 View 函数(或其他此类回调)之外,例如在一次性脚本中使用您的模型时。

解决办法是自己推送应用上下文,可以通过做...
from myapp import app, db

# Set up models
with app.app_context():
db.create_all()

这将推送一个新的应用程序上下文(使用 app 的应用程序,请记住可能有多个应用程序)。

测试

您想要操作堆栈的另一种情况是用于测试。您可以创建一个处理请求的单元测试并检查结果:
import unittest
from flask import request

class MyTest(unittest.TestCase):
def test_thing(self):
with app.test_request_context('/?next=http://example.com/') as ctx:
# You can now view attributes on request context stack by using `request`.

# Now the request context stack is empty

关于python - Flask 的上下文堆栈的目的是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20036520/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com