提问者:小点点

在烧瓶应用程序中保留全局状态[重复]


我正在尝试在我的flask应用程序中保存缓存字典。

据我所知,应用程序上下文,特别是flaskg对象应该用于此目的。

设置:

import flask as f

app = f.Flask(__name__)

现在如果我这样做:

with app.app_context():
    f.g.foo = "bar"
    print f.g.foo

它打印

继续进行以下工作:

with app.app_context():
    print f.g.foo

AttributeError: '_AppCtxGlobals' object has no attribute 'foo'

我不明白,医生也帮不上忙。如果我读对了,这个州应该被保留下来。

我的另一个想法是简单地使用模块范围的变量:

cache = {}

def some_function():
    cache['foo'] = "bar"

但似乎每个请求都会重置这些。

如何正确地做到这一点?

编辑:烧瓶10.1


共3个答案

匿名用户

根据你的问题,我想你对“全球”的定义感到困惑。

在现有的Flask设置中,您有一个具有多个线程和可能处理请求的多个进程的Flask服务器。假设您有一个股票全局变量,如“itemlist = []", ,并且您希望在每个请求中不断添加它——例如,每次有人向终结点发出POST请求。这在理论和实践上是完全可能的。这也是一个非常糟糕的主意。

问题是,您无法轻松控制哪些线程和进程“获胜”——列表的顺序可能非常不稳定,或者完全损坏。现在您需要讨论锁、互斥体和其他原语。这很难,也很烦人。

您应该尽可能保持网络服务器本身无状态。每个请求应该是完全独立的,并且不共享服务器中的任何状态。相反,使用数据库或缓存层来处理状态。这看起来更复杂,但实际上更简单。例如,查看SQLite;这很简单。

解决“烧瓶”问题。g'对象,即基于每个请求的全局对象。

http://flask.pocoo.org/docs/api/#flask.g

它在请求之间被“擦干净”,不能用于在请求之间共享状态。

匿名用户

我做了一些类似于您的“模块范围变量”的想法,我在一个flask服务器中使用它来集成两个软件,我知道我将只有一个同时的“用户”(作为发送方软件)。

我的应用程序。py看起来像这样:

from flask import Flask
from flask.json import jsonify
app = Flask(__name__)

cache = {}

@app.route("/create")
def create():
    cache['foo'] = 0
    return jsonify(cache['foo'])

@app.route("/increment")
def increment():
    cache['foo'] = cache['foo'] + 1
    return jsonify(cache['foo'])

@app.route("/read")
def read():
    return jsonify(cache['foo'])

if __name__ == '__main__':
    app.run()

你可以这样测试:

import requests

print(requests.get('http://127.0.0.1:5000/create').json())
print(requests.get('http://127.0.0.1:5000/increment').json())
print(requests.get('http://127.0.0.1:5000/increment').json())
print(requests.get('http://127.0.0.1:5000/read').json())
print(requests.get('http://127.0.0.1:5000/increment').json())
print(requests.get('http://127.0.0.1:5000/create').json())
print(requests.get('http://127.0.0.1:5000/read').json())

产出:

0
1
2
2
3
0
0

请谨慎使用,因为我认为这不会在适当的多用户web服务器环境中发生。

匿名用户

这条线

with app.app_context():
    f.g.foo = "bar"

由于您使用的是“with”关键字,因此一旦执行了此循环,它将调用AppContext类的\uuuuuuuuuuuuuuuuuuuuuu方法。看这个。所以“foo”一旦完成就弹出了。这就是为什么你不再有它的原因。您可以改为尝试:

ctx = app.app_context()
f.g.foo = 'bar'
ctx.push()

在调用以下命令之前,g.foo应该是可用的

ctx.pop()

但是,我不确定您是否希望将其用于缓存。