85

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

据我了解,应为此使用Application Context,尤其是flask.g 对象。

设置:

import flask as f

app = f.Flask(__name__)

现在,如果我这样做:

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

它打印bar

继续以下内容:

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

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

我不明白,文档根本没有帮助。如果我正确阅读它们,则应该保留状态。

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

cache = {}

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

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

如何正确执行此操作?

编辑:烧瓶 10.1

4

3 回答 3

83

根据您的问题,我认为您对“全球”的定义感到困惑。

在现有的 Flask 设置中,您有一个 Flask 服务器,它具有多个线程,并且可能有多个处理请求的进程。假设您有一个像“itemlist = []”这样的库存全局变量,并且您希望在每个请求中继续添加它 - 例如,每次有人向端点发出 POST 请求时。这在理论上和实践上都是完全可能的。这也是一个非常糟糕的主意。

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

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

为了解决“flask.g”对象,它是基于每个请求的全局对象。

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

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

于 2014-05-01T22:25:21.343 回答
18

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

我的 app.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 服务器环境中运行。

于 2016-09-01T12:10:59.600 回答
12

这条线

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

由于您使用的是“with”关键字,因此一旦执行此循环,它就会调用__exit__AppContext 类的方法。看到这个。所以一旦完成,'foo'就会弹出。这就是为什么你没有它再次可用。您可以尝试:

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

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

ctx.pop()

但是,我不确定您是否要将其用于缓存目的。

于 2013-10-09T17:02:18.370 回答