2013-02-26 18 views
104

I saw, dass g aus dem Anfragekontext in den App-Kontext in Flask 0.10 verschoben wird, was mich über die beabsichtigte Verwendung von g verwirrt hat.Wann sollte Flask.g verwendet werden?

Mein Verständnis (für Flask 0.9) ist, dass:

  • g Leben im Anforderungskontext, dh neu erstellt, wenn die Anfragen gestartet und verfügbar, bis es endet
  • g soll verwendet werden, als "Anfrage Tafel", wo ich Sachen für die Dauer der Anfrage relevant setzen kann (dh ein Flag am Anfang der Anfrage setzen und am Ende behandeln, möglicherweise von einem before_request/after_request Paar)
  • in Zusätzlich zum Halteanforderungsstatus g kann und sollte für die Ressourcenverwaltung verwendet werden, d. H. Datenbankverbindungen usw. halten.

Welcher dieser Sätze ist in Flask 0.10 nicht mehr wahr? Kann jemand mich auf eine Ressource verweisen, die die Gründe für die Änderung bespricht? Was sollte ich als "Anfragetafel" in Flask 0.10 verwenden - sollte ich meinen eigenen app-/erweiterungsspezifischen threadlokalen Proxy erstellen und ihn in den Kontextstapel before_request schieben? Was ist der Sinn der Ressourcenverwaltung im Anwendungskontext, wenn meine Anwendung lange Zeit (nicht wie eine Anfrage) läuft und die Ressourcen daher nie freigegeben werden?

+0

Ich stimme zu, das ist eine ziemlich merkwürdige Veränderung. Hoffentlich implementiert mitsuhiko eine Art Request-Context-Objekt, um 'g' in 0.10 zu ersetzen, sonst hört es sich so an, als würde viel Code mit der Entwicklung einiger hinterhältiger Bugs beginnen. – Anorov

+7

FWIW, Armin Ronacher (Autor von Flask) hat eine Fortsetzung von "Advanced Flask Patterns" veröffentlicht, die einen Beispielcode zeigt, wie man den neuen "flask.g" verwendet. https://speakerdeck.com/mitsuhoniko/advanced-flask-patterns-1 –

+1

auch ein neuer Anfrage Kontext impliziert einen neuen App-Kontext, so sollte es einfach normal funktionieren – Ronny

Antwort

72

Advanced Flask Patterns, wie von Markus verbunden, erklärt einige der Änderungen an g in 0,10:

  • g jetzt im Anwendungskontext lebt.
  • Every request pushes a new application context, wischen die alte, so g kann immer noch verwendet werden, um Flags pro Anfrage ohne Änderung des Codes zu setzen.
  • Der Anwendungskontext wird geknallt nachteardown_request heißt. (Armin Präsentation erklärt dies, weil Dinge wie das Erstellen DB-Verbindungen sind Aufgaben, die Setup die Umgebung für die Anforderung, und sollten sich nicht in before_request und after_request behandelt werden)
+0

In dem Quellcode, mit dem Sie verbunden, wenn 'app_ctx ist None oder app_ctx.app! = self.app' ist False, der alte Anwendungskontext scheint wieder verwendet zu werden? Dies scheint nicht richtig zu sein, da der Anwendungskontext "nicht zwischen Anfragen geteilt wird" ... –

+1

Beziehen Sie sich auf das [Drücken von 'app.app_context()'] (https://github.com/ Paletten/Flasche/Blob/Master/Flasche/ctx.py # L317)? Wenn ja, sollte beachtet werden, dass [app_context() '] (https://github.com/pallets/flask/blob/master/flask/app.py#L2080-L2093) einen neuen Anwendungskontext bei jedem Aufruf instanziiert Nutzt nie einen Kontext. – theY4Kman

+1

Ja, das stimmt, aber wenn 'app_ctx nicht None und app_ctx.app == self.app' ist, wird die' app_ctx = self.app.app_context() 'Zeile _nicht_ ausgeführt; nur 'self._ implicit_app_ctx_stack.append (None)' wird in diesem Fall ausgeführt. –

33

in diesem Thread zu den Informationen Als Nachtrag: Ich war ein wenig verwirrt durch das Verhalten von flask.g, aber einige schnelle Tests haben mir geholfen, es zu klären. Hier ist, was ich ausprobiert:

from flask import Flask, g 
app = Flask(__name__) 

with app.app_context(): 
    print('in app context, before first request context') 
    print('setting g.foo to abc') 
    g.foo = 'abc' 
    print('g.foo should be abc, is: {0}'.format(g.foo)) 

    with app.test_request_context(): 
     print('in first request context') 
     print('g.foo should be abc, is: {0}'.format(g.foo)) 
     print('setting g.foo to xyz') 
     g.foo = 'xyz' 
     print('g.foo should be xyz, is: {0}'.format(g.foo)) 

    print('in app context, after first request context') 
    print('g.foo should be abc, is: {0}'.format(g.foo)) 

    with app.test_request_context(): 
     print('in second request context') 
     print('g.foo should be abc, is: {0}'.format(g.foo)) 
     print('setting g.foo to pqr') 
     g.foo = 'pqr' 
     print('g.foo should be pqr, is: {0}'.format(g.foo)) 

    print('in app context, after second request context') 
    print('g.foo should be abc, is: {0}'.format(g.foo)) 

Und hier ist der Ausgang, die es gibt:

in app context, before first request context 
setting g.foo to abc 
g.foo should be abc, is: abc 
in first request context 
g.foo should be abc, is: abc 
setting g.foo to xyz 
g.foo should be xyz, is: xyz 
in app context, after first request context 
g.foo should be abc, is: xyz 
in second request context 
g.foo should be abc, is: xyz 
setting g.foo to pqr 
g.foo should be pqr, is: pqr 
in app context, after second request context 
g.foo should be abc, is: pqr 

Wie theY4Kman oben gesagt: „Jede Anfrage schiebt einen neuen Anwendungskontext“. Und as the Flask docs say, der Anwendungskontext "wird nicht zwischen Anfragen geteilt". Nun, was nicht explizit gesagt wurde (obwohl ich denke, dass es aus diesen Aussagen impliziert ist), und was meine Tests deutlich zeigen, ist, dass Sie niemals explizit mehrere Anforderungskontexte verschachtelt in einem Anwendungskontext erstellen, weil flask.g (und co) hat keine Magie, wodurch es in den zwei verschiedenen "Ebenen" des Kontextes funktioniert, mit verschiedenen Zuständen, die unabhängig auf den Anwendungs- und Anfrageebenen existieren.

Die Realität ist, dass „Anwendungskontext“ ist möglicherweise ein ziemlich irreführend Namen, weil app.app_context() ist ein pro-Anforderungskontext, genau das gleiche wie der „Anforderungskontext“. Stellen Sie es sich als "request context lite" vor, nur für den Fall, dass Sie einige der Variablen benötigen, die normalerweise einen Anforderungskontext benötigen, aber keinen Zugriff auf ein Anforderungsobjekt benötigen (z. B. beim Ausführen von Batch-DB-Operationen in einem Shell-Skript). Wenn Sie versuchen, den Anwendungskontext auf mehrere Anforderungskontexte auszudehnen, werden Sie nach Problemen gefragt. Also, anstatt mein Test oben, sollten Sie stattdessen Code wie folgt mit Kontexten der Flask schreiben:

from flask import Flask, g 
app = Flask(__name__) 

with app.app_context(): 
    print('in app context, before first request context') 
    print('setting g.foo to abc') 
    g.foo = 'abc' 
    print('g.foo should be abc, is: {0}'.format(g.foo)) 

with app.test_request_context(): 
    print('in first request context') 
    print('g.foo should be None, is: {0}'.format(g.get('foo'))) 
    print('setting g.foo to xyz') 
    g.foo = 'xyz' 
    print('g.foo should be xyz, is: {0}'.format(g.foo)) 

with app.test_request_context(): 
    print('in second request context') 
    print('g.foo should be None, is: {0}'.format(g.get('foo'))) 
    print('setting g.foo to pqr') 
    g.foo = 'pqr' 
    print('g.foo should be pqr, is: {0}'.format(g.foo)) 

die erwarteten Ergebnisse geben wird.

Verwandte Themen