web-dev-qa-db-fra.com

Quand utiliser Flask.g?

I saw que g va passer du contexte de la requête au contexte de l'application dans Flask 0.10, ce qui m'a laissé confus sur l'utilisation prévue de g.

Ma compréhension (pour Flask 0.9) est la suivante:

  • g vit dans le contexte de la requête, c’est-à-dire créé de nouveau au début des requêtes et disponible jusqu’à sa fin.
  • g est destiné à être utilisé comme un "tableau de requête", où je peux mettre des choses pertinentes pour la durée de la requête (c'est-à-dire, définir un drapeau au début de la requête et le gérer à la fin, éventuellement de before_request/after_request paire)
  • en plus de la détention du niveau de la requête, g peut et devrait être utilisé pour la gestion des ressources, c'est-à-dire la conservation des connexions à la base de données, etc.

Lesquelles de ces phrases ne sont plus vraies dans Flask 0.10? Quelqu'un peut-il m'indiquer une ressource traitant des raisons de Que dois-je utiliser comme "tableau de requête" dans Flask 0.10 - dois-je créer mon propre proxy de thread local spécifique à une application/une extension et le placer dans la pile de contexte before_request? Quel est l'intérêt de la gestion des ressources dans le contexte de l'application, si mon application dure longtemps (et non comme une requête) et que les ressources ne sont donc jamais libérées?

148
Yaniv Aknin

Avancé Flask Patterns , comme lié par Markus , explique certains des changements apportés à g en 0.10:

  • g vit maintenant dans le contexte de l'application.
  • Chaque requête insère un nouveau contexte d'application , efface l'ancien, de sorte que g puisse toujours être utilisé pour définir des drapeaux par requête sans modifier le code.
  • Le contexte de l'application est affiché après le teardown_request est appelé. (La présentation d'Armin explique cela parce que, par exemple, la création de connexions à une base de données est une tâche qui configure l'environnement de la requête et ne doit pas être gérée à l'intérieur de before_request et after_request)
100
theY4Kman

En complément aux informations de ce fil de discussion: Le comportement de flask.g M'a également un peu dérouté, mais quelques tests rapides m'ont aidé à clarifier le tout. Voici ce que j'ai essayé:

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

Et voici le résultat que cela donne:

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

Comme l'a dit Y4Kman ci-dessus, "chaque demande introduit un nouveau contexte d'application". Et comme le Flask docs disent , le contexte de l'application "ne sera pas partagé entre les demandes". Maintenant, ce qui n'a pas été explicitement indiqué (bien que je suppose que c'est implicite de ces déclarations), et ce que mes tests montrent clairement, est que vous devriez ne jamais créer explicitement plusieurs contextes de requête imbriqués dans un contexte d'application, parce que flask.g (And co) n’a aucune magie dans laquelle il fonctionne dans les deux "niveaux" de contexte différents, avec des états différents existant indépendamment aux niveaux application et demande.

La réalité est que "contexte d'application" est potentiellement un nom assez trompeur, car app.app_context() est a par requête). context , exactement le même que le "contexte de la requête" . Considérez-le comme une "requête contextuelle", requis uniquement dans le cas où vous avez besoin de certaines variables nécessitant normalement un contexte de requête, mais sans avoir besoin d'accéder à un objet de requête (par exemple, lors de l'exécution d'opérations de base de données par lots dans Script shell). Si vous essayez d'étendre le contexte d'application à plusieurs contextes de demande, vous vous posez des problèmes. Donc, plutôt que mon test ci-dessus, vous devriez plutôt écrire un code comme celui-ci avec les contextes de Flask:

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

Ce qui donnera les résultats attendus:

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 None, is: None
setting g.foo to xyz
g.foo should be xyz, is: xyz
in second request context
g.foo should be None, is: None
setting g.foo to pqr
g.foo should be pqr, is: pqr
58
Jaza