2013-10-09 5 views
29

Ich versuche, ein Cache-Verzeichnis in meiner flask Anwendung zu speichern.Erhalt des globalen Status in einer Flaschen-Anwendung

Soweit ich es verstehe, sollte dafür die Application Context, insbesondere die flask.g object verwendet werden.

Setup:

import flask as f 

app = f.Flask(__name__) 

Nun, wenn ich

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

tun es druckt bar.

Weiter mit dem folgenden

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

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

ich es nicht verstehen und die Dokumentation sind überhaupt nicht helfen. Wenn ich sie richtig lese, hätte der Zustand erhalten bleiben sollen.

Eine weitere Idee ich hatte, war einfach Modul weite Variablen verwenden:

cache = {} 

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

aber es scheint, wie diese mit jeder Anfrage zurückgesetzt zu bekommen.

Wie wird das richtig gemacht?

Edit: Flask 10.1

+0

Haben Sie [Flask-Cache] (http://pythonhosted.org/Flask-Cache/) ausgecheckt? –

+7

Nein, danke für den Link, aber es ist so eine einfache Aufgabe, dass ich die Abhängigkeiten niedrig halten möchte. – Profpatsch

+0

welche Version von Flask benutzen Sie? – codegeek

Antwort

40

Basierend auf Ihrer Frage, ich denke, Sie sind verwirrt über die Definition von "global".

In einer Bestands-Flask-Konfiguration haben Sie einen Flask-Server mit mehreren Threads und potenziell mehreren Prozessen, die Anfragen bearbeiten. Angenommen, Sie hätten eine globale Variable wie "itemlist = []", und Sie wollten sie bei jeder Anfrage hinzufügen - etwa bei jeder POST-Anfrage an einen Endpunkt. Dies ist in Theorie und Praxis durchaus möglich. Es ist auch eine wirklich schlechte Idee.

Das Problem ist, dass Sie nicht einfach steuern können, welche Threads und Prozesse "gewinnen" - die Liste könnte in einer wirklich wackeligen Reihenfolge auftauchen oder komplett korrumpiert werden. Jetzt müssen Sie über Sperren, Mutexe und andere Primitive sprechen. Das ist hart und nervig.

Sie sollten den Webserver selbst so statusfrei wie möglich halten.Jede Anfrage sollte völlig unabhängig sein und keinen Status im Server teilen. Verwenden Sie stattdessen eine Datenbank oder Caching-Ebene, die den Status für Sie übernimmt. Dies erscheint komplizierter, ist aber in der Praxis einfacher. Schauen Sie sich SQLite zum Beispiel an; es ist ziemlich einfach.

Um das 'flask.g' Objekt zu adressieren, ist das ein globales Objekt auf einer pro Anfrage Basis.

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

Es heißt „sauber gewischt“ zwischen den Anforderungen und kann nicht verwendet werden Zustand zwischen ihnen zu teilen.

+1

Ich verstehe die Datenbank-Ansatz, aber nicht mit Caching-Schichten vertraut. Können Sie Caching-Layer-Bibliotheken/Frameworks empfehlen? – max

+0

Es scheint, dass in Flask 0.11 'flask.g' an Anwendungskontext gebunden ist. Ändert es etwas? – omikron

+0

Ich liebe SQlite, aber ich denke nicht, dass Sie es für die gleichzeitige Verwendung in Apps verwenden möchten, die Schreibvorgänge vornehmen müssen. Writes sperrt die Datenbank. Ich denke wirklich, dass etwas wie Redis-Server den Job machen wird, speziell für Listings. Ein anderer (vielleicht dummer) Ansatz könnte sein, Daten separat in einen Ordner zu schreiben. So schreibt jeder Thread seine eigene Datei, aber wenn Sie Daten abrufen, lesen Sie alle Dateien. Auf diese Weise erhalten Sie immer alle Daten, während neue Schreibvorgänge nicht blockiert werden. – erm3nda

7

Diese Linie

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

Da Sie die "mit" Schlüsselwort verwenden, wenn diese Schleife ausgeführt wird, ist es die __exit__ Methode der AppContext Klasse aufruft. Siehe this. Also wird das 'foo' ausgepoppt sobald es fertig ist. Deshalb haben Sie es nicht wieder verfügbar. Sie können stattdessen versuchen:

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

Bis Sie den folgenden Aufruf, g.foo

ctx.pop() 

verfügbar sein sollte, ich bin howver nicht sicher, ob Sie dies zum Zwecke der Caching verwenden möchten.

+4

Was soll ich dann verwenden? Ich dachte, das wäre das Mittel, um globale Werte in einer App zu speichern? – Profpatsch

+2

Der Anwendungskontext wird erstellt und bei Bedarf gelöscht. Es bewegt sich nie zwischen Threads und es wird nicht zwischen Anfragen geteilt. (http://flask.pooco.org/docs/appcontext/) –

3

Ich habe etwas Ähnliches wie Ihre "module-wide variables" Idee gemacht, die ich in einem Flaschen-Server verwende, den ich für die Integration von zwei Software-Stücken verwende, von denen ich weiß, dass ich nur einen simultanen "Benutzer" habe die Sender-Software).

sieht mein app.py wie folgt aus:

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

Sie es wie folgt testen:

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

Ausgänge:

0 
1 
2 
2 
3 
0 
0 

Mit Vorsicht, wie ich dies erwarten Verhalten in einer geeigneten Mehrbenutzer-Webserverumgebung.

+2

Dies funktioniert in Situationen, in denen Sie einen einzelnen uwsgi worker global haben.Sie müssen sich auch um den Mehrfachzugriff auf die Variable kümmern, sodass Sie abhängig von der Verwendung möglicherweise Sperren oder Ähnliches implementieren müssen. Es ist ein anderes Werkzeug in der Tasche obwohl. –