web-dev-qa-db-fra.com

Préservation de l'état global dans une application flask

J'essaie de sauvegarder un dictionnaire de cache dans mon application flask.

Autant que je sache, contexte d'application , en particulier flask.g object , devrait être utilisé à cet effet.

Installer:

import flask as f

app = f.Flask(__name__)

Maintenant si je le fais:

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

Il imprime bar.

Continuant avec ce qui suit:

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

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

Je ne le comprends pas et les docs n’aident pas du tout. Si je les lis correctement, l'état aurait dû être préservé.

Une autre idée que j'avais était simplement d'utiliser des variables à l'échelle du module:

cache = {}

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

Mais il semble que ceux-ci soient réinitialisés à chaque demande.

Comment faire cela correctement?

Modifier: Flask 10.1

55
Profpatsch

Sur la base de votre question, je pense que vous êtes confus quant à la définition de "global".

Dans une configuration de stock Flask, vous avez un serveur Flask avec plusieurs threads et potentiellement plusieurs processus de traitement des demandes. Supposons que vous disposiez d'une variable globale stock telle que "itemlist = [] ", et vous vouliez continuer à y ajouter à chaque demande - par exemple, chaque fois que quelqu'un adressait une demande POST à un noeud final. C'est tout à fait possible en théorie et en pratique. vraiment mauvaise idée.

Le problème est que vous ne pouvez pas facilement contrôler quels threads et quels processus "gagnent" - la liste pourrait être dressée dans un ordre vraiment dérisoire ou être corrompue complètement. Alors maintenant, vous devez parler des verrous, mutex et autres primitives. C'est dur et ennuyeux.

Vous devez garder le serveur Web lui-même aussi apatride que possible. Chaque demande doit être totalement indépendante et ne partager aucun état sur le serveur. Utilisez plutôt une couche de base de données ou de mise en cache qui gérera l’état pour vous. Cela semble plus compliqué mais est en réalité plus simple en pratique. Découvrez SQLite par exemple; c'est assez simple.

Pour adresser l'objet 'flask.g', il s'agit d'un objet global par requête .

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

Il est "effacé" entre les demandes et ne peut pas être utilisé pour partager un état entre elles.

59
mallyvai

Cette ligne

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

Puisque vous utilisez le mot-clé "with", une fois cette boucle exécutée, elle appelle le __exit__ méthode de la classe AppContext. Voir this . Donc, le "foo" est sorti une fois fait. C'est pourquoi vous ne l'avez pas à nouveau disponible. Vous pouvez plutôt essayer:

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

Jusqu'à ce que vous appeliez le suivant, g.foo devrait être disponible

ctx.pop()

Je ne suis cependant pas sûr si vous voulez utiliser ceci dans le but de mettre en cache.

10
codegeek

J'ai utilisé quelque chose de similaire à votre idée de "variables globales" que j'utilise dans un serveur flask) que j'utilise pour intégrer deux logiciels, où je sais que je n'aurai jamais qu'un seul à la fois. "utilisateur" (étant le logiciel expéditeur).

Mon app.py ressemble à ceci:

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

Vous pouvez le tester comme ceci:

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

Les sorties:

0
1
2
2
3
0
0

Utilisez-le avec précaution car je m'attends à ce que cela ne se comporte pas dans un environnement de serveur Web multi-utilisateur approprié.

8
Johan Gov