184 votes

Quel est le but des piles de contexte de Flask?

J'ai été en utilisant la demande/le contexte de l'application pour un certain temps sans bien comprendre comment il fonctionne, ou pourquoi il a été conçu de la manière qu'il a été. Quel est le but de la "pile" quand il s'agit de la demande ou de contexte de l'application? Ce sont ces deux charges distinctes, ou sont-ils tous deux partie d'une pile? Est le contexte de la demande poussé sur une pile ou une pile de lui-même? Suis-je capable de push/pop de multiples contextes sur eachother? Si oui, pourquoi voudrais-je faire?

Désolé pour toutes les questions, mais je suis toujours perplexe après la lecture de la documentation de la Demande et Contexte de Contexte de l'Application.

270voto

Mark Hildreth Points 9481

Plusieurs Applications

Le contexte de l'application (et de son but), est en effet à confusion jusqu'à ce que vous vous rendez compte que le Flacon peut avoir de multiples applications. Imaginez la situation où vous voulez avoir un seul WSGI de l'interpréteur Python exécuter plusieurs Fiole d'application. Nous ne parlons pas des Modèles ici, nous parlons d'entièrement différent Flacon applications.

Vous pouvez définir ce similaire à la Fiole de section de documentation sur l'Application "Dispatching" exemple:

from werkzeug.wsgi import DispatcherMiddleware
from frontend_app import application as frontend
from backend_app import application as backend

application = DispatcherMiddleware(frontend, {
    '/backend':     backend
})

Notez qu'il existe deux types complètement différents Flacon applications en cours de création "frontend" et "backend". En d'autres termes, l' Flask(...) application constructeur a été appelé à deux reprises, la création de deux instances d'un Flacon d'application.

Contextes

Lorsque vous travaillez avec Flacon, vous finissent souvent par l'utilisation de variables globales pour l'accès aux différentes fonctionnalités. Par exemple, vous avez probablement un code qui lit...

from flask import request

Puis, au cours d'une vue, vous pouvez utiliser request d'accéder à l'information de la demande actuelle. De toute évidence, request n'est pas normal variable globale; en réalité, il s'agit d'un contexte local de la valeur. En d'autres termes, il y a de la magie derrière les scènes qui dit "quand je l'appelle request.path, obtenir l' path de l'attribut de l' request objet de la demande ACTUELLE." Deux demandes différentes auront des résultats différents pour request.path. En fait, même si vous exécutez Flacon avec plusieurs threads, le Flacon est assez intelligent pour garder l' request variable tellement isolé que deux threads peuvent appeler request.path dans le même temps, et chacun serait d'obtenir la demande spécifique de leur fils.

De les mettre Ensemble

Nous avons déjà vu que le Flacon peut gérer plusieurs applications d'un même interprète, et aussi qu'en raison de la façon dont Flacon permet d'utiliser les "contexte local" globals il doit y avoir un mécanisme pour déterminer ce que le "courant" demande est (pour faire des choses telles que l' request.path).

Mettre ces idées ensemble, il convient également de sens que le Flacon doit avoir une certaine manière de déterminer ce que le "courant" demande est!

Vous avez sans doute aussi avoir un code semblable au suivant:

from flask import url_for

Comme notre request exemple, l' url_for de la fonction de la logique qui dépend de l'environnement actuel. Dans ce cas, cependant, il est évident de voir que la logique est fortement dépendante de l'application qui est considéré comme le "courant" de l'app. Dans le frontend/backend exemple montré ci-dessus, à la fois le "frontend" et "backend" apps pourrait avoir un "/login" la route, et donc, url_for('/login') doit retourner quelque chose de différent selon si l'affichage est en charge de la demande pour le frontend ou backend app.

Pour répondre à vos questions...

Quel est le but de la "pile" quand il s'agit de la demande ou le contexte de l'application?

À partir du Contexte de Demande de docs:

Parce que le contexte de la demande est maintenue en interne comme une pile peut push et pop à plusieurs reprises. Ce qui est très pratique à mettre en œuvre des choses comme les redirections internes.

En d'autres termes, même si vous l'aura généralement 0 ou 1 articles sur ces pile de "actuelles les demandes" ou "actuel" des applications, il est possible que vous pourriez avoir plus.

L'exemple donné est l'endroit où vous avez votre demande de retour les résultats d'une "redirection interne". Disons qu'un utilisateur demande un, mais que vous voulez revenir à l'utilisateur B. Dans la plupart des cas, vous émettez une redirection de l'utilisateur, et l'utilisateur de la ressource B, indiquant que l'utilisateur exécute une deuxième demande pour récupérer B. d'Une manière légèrement différente de la manipulation de ce serait de faire une redirection interne, ce qui signifie que pendant le traitement, Flacon va faire une nouvelle demande à lui-même pour B de ressource, et d'utiliser les résultats de cette deuxième demande que les résultats de l'utilisateur d'origine de la demande.

Ce sont ces deux charges distinctes, ou sont-ils tous deux partie d'une pile?

Ils sont deux charges distinctes. Cependant, c'est un détail d'implémentation. Ce qui est plus important n'est pas tellement qu'il y est une pile, mais le fait qu'à tout moment, vous pouvez obtenir le "courant" de l'app ou de la demande (en haut de la pile).

Est le contexte de la demande poussé sur une pile ou une pile de lui-même?

Un "contexte de demande" est un élément de la "demande de la pile de contexte". De la même façon avec l'application "contexte" et "app contexte de la pile".

Suis-je capable de push/pop de multiples contextes sur eachother? Si oui, pourquoi voudrais-je faire?

Dans une Fiole de l'application, vous devriez pas faire cela. Un exemple de cas où vous pourriez voulez est pour une redirection interne (décrit ci-dessus). Même dans ce cas, cependant, vous auriez probablement finir par avoir Flacon de traiter une nouvelle demande, et ainsi de Fiole de les pousser ou popping pour vous.

Cependant, il y a certains cas où vous seriez amené à manipuler la pile vous-même.

L'exécution du code en dehors d'une demande

Un problème typique des gens ont, c'est qu'ils utilisent le Flacon de SQLAlchemy extension pour configurer une base de données SQL et la définition d'un modèle à l'aide de code quelque chose comme ce qui est montré ci-dessous...

app = Flask(__name__)
db = SQLAlchemY() # Initialize the Flask-SQLAlchemy extension object
db.init_app(app)

Ensuite, à l' app et db valeurs dans un script qui doit être exécuté à partir de la coquille. Par exemple, un "setup_tables.py" le script...

from myapp import app, db

# Set up models
db.create_all()

Dans ce cas, le Flacon-SQLAlchemy extension sait à propos de l' app application, mais au cours create_all() il lèvera une erreur se plaindre de l'absence d'un contexte d'application. Cette erreur est justifiée; la gestion du contexte de l'application est déjà géré par Flacon lorsque l'application est le traitement d'une demande, mais depuis l' create_all() méthode n'est PAS à exécuter lors d'un point de vue, le Flacon n'est pas le contexte pour vous.

La résolution est de pousser le contexte de l'application vous-même, ce qui peut être fait en faisant...

from myapp import app, db

# Set up models
with app.app_context():
    db.create_all()

Ce sera le pousser un nouveau contexte de l'application (à l'aide de l'application de l' app, rappelez-vous, il pourrait y avoir plus d'une application).

Les tests

Un autre cas où vous souhaitez manipuler la pile est utilisé pour les tests. Vous pouvez créer un test unitaire qui gère une demande et vous de vérifier les résultats:

import unittest
from flask import request

class MyTest(unittest.TestCase):
    def test_thing(self):
        with app.test_request_context('/?next=http://example.com/') as ctx:
            # You can now view attributes on request context stack by using at `request`.

        # Now the request context stack is empty

14voto

tbicr Points 4969

Peu plus @Mark Hildreth's réponse.

Pile de contexte ressembler {thread.get_ident(): []}[] appelé "pile", car utilisé seulement append (push), pop et [-1] (__getitem__(-1)) opérations. Donc pile de contexte conservera les données réelles de fil ou de greenlet fil.

current_app, g, request, session et etc est - LocalProxy objet qui vient de surdéfini, de méthodes d' __getattr__, __getitem__, __call__, __eq__ et etc. et la valeur de retour à partir du contexte de la pile supérieure ([-1]) par nom d'argument (current_app, request par exemple). LocalProxy nécessaires pour l'importation de ces objets une fois et ils ne manquent pas d'actualité. Afin de mieux de simplement importer request où jamais vous êtes dans le code au lieu de jouer avec l'envoi de la demande argument à vous de fonctions et de méthodes. Vous pouvez facilement écrire propres extensions avec elle, mais n'oubliez pas que frivole utilisation peut rendre le code plus difficile à comprendre.

Passer du temps à comprendre https://github.com/mitsuhiko/werkzeug/blob/master/werkzeug/local.py.

Alors, comment peuplé à la fois de piles? Sur demande, Flask:

  1. créer request_context par l'environnement (init map_adapter, match de chemin d'accès)
  2. entrer ou de pousser à cette demande:
    1. claire précédente request_context
    2. créer app_context si c'est raté et poussé à le contexte de l'application de la pile
    3. cette demande a poussé à demander la pile de contexte
    4. initialisation de session si c'est raté
  3. envoi demande
  4. demande claire et pop de pile

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X