it-roy-ru.com

Сохранение глобального состояния в приложении flask)

Я пытаюсь сохранить словарь кэша в моем приложении flask.

Насколько я понимаю, для этого нужно использовать Application Context , в частности flask.g object .

Настроить:

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"

Но похоже, что они сбрасываются с каждым запросом.

Как это сделать правильно?

Изменить: Flask 10.1

55
Profpatsch

Исходя из вашего вопроса, я думаю, вы не понимаете, что такое "глобальный".

В стандартной установке Flask у вас есть сервер Flask с несколькими потоками и потенциально несколькими процессами, обрабатывающими запросы. Предположим, у вас есть глобальная переменная типа "itemlist =" [] ", и вы хотели добавлять к нему каждый запрос, скажем, каждый раз, когда кто-то делал запрос POST к конечной точке. Это вполне возможно в теории и на практике. Это также действительно плохая идея.

Проблема в том, что вы не можете легко контролировать, какие потоки и процессы "выигрывают" - список может быть увеличен в очень сомнительном порядке или полностью испорчен. Так что теперь вам нужно поговорить о замках, мьютексах и других примитивах. Это тяжело и раздражает.

Вы должны держать сам веб-сервер как можно без состояний. Каждый запрос должен быть полностью независимым и не иметь общего состояния на сервере. Вместо этого используйте слой базы данных или кэширования, который будет обрабатывать состояние за вас. Это кажется более сложным, но на самом деле проще на практике. Проверьте SQLite например; это довольно просто.

Чтобы обратиться к объекту 'flask.g', это глобальный объект для каждого запроса .

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

Он "очищается" между запросами и не может использоваться для обмена между ними состояниями.

59
mallyvai

Эта линия

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()

Однако я не уверен, хотите ли вы использовать это для кэширования.

10
codegeek

Я сделал нечто похожее на вашу идею "переменных модуля", которую я использую на сервере flask, который я использую для интеграции двух программ, где я знаю, что у меня когда-нибудь будет только один одновременный "пользователь" (являющийся программным обеспечением отправителя).

Мой 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 __== '__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

Используйте с осторожностью, поскольку я ожидаю, что это не будет вести себя в надлежащей многопользовательской среде веб-сервера.

8
Johan Gov