Wie greife ich in einer Blaupause auf app.config zu?

114

Ich versuche, auf die Konfiguration der Zugriffsanwendung innerhalb eines Entwurfs zuzugreifen, authorisation.pyder in einer Paket-API enthalten ist. Ich initialisiere die Blaupause, in __init__.pyder in verwendet wird authorisation.py.

__init__.py

from flask import Blueprint
api_blueprint = Blueprint("xxx.api", __name__, None)
from api import authorisation

authorisation.py

from flask import request, jsonify, current_app

from ..oauth_adapter import OauthAdapter
from api import api_blueprint as api

client_id = current_app.config.get('CLIENT_ID')
client_secret = current_app.config.get('CLIENT_SECRET')
scope = current_app.config.get('SCOPE')
callback = current_app.config.get('CALLBACK')

auth = OauthAdapter(client_id, client_secret, scope, callback)


@api.route('/authorisation_url')
def authorisation_url():
    url = auth.get_authorisation_url()
    return str(url)

Ich erhalte RuntimeError: Arbeiten außerhalb des Anwendungskontexts

Ich verstehe, warum das so ist, aber wie kann man dann richtig auf diese Konfigurationseinstellungen zugreifen?

---- Update ---- Vorübergehend habe ich das getan.

@api.route('/authorisation_url')
def authorisation_url():
    client_id, client_secret, scope, callback = config_helper.get_config()
    auth = OauthAdapter(client_id, client_secret, scope, callback)
    url = auth.get_authorisation_url()
    return str(url)
Chirdeep Tomar
quelle

Antworten:

131

Verwenden Sie flask.current_appanstelle von appin der Blaupausenansicht.

from flask import current_app

@api.route("/info")
def get_account_num():
    num = current_app.config["INFO"]

Der current_appProxy ist nur im Rahmen einer Anfrage verfügbar .

weihuang
quelle
25
Beachten Sie, dass der current_appProxy nur im Kontext einer Anforderung verfügbar ist.
September
1
@sephr Gibt es Tipps, wie Sie von anderen Stellen aus auf diesen Anforderungskontext zugreifen können (ohne ihn als Parameter, aber als eine Art globalen Parameter zu übergeben)?
Carkod
21

Die Überladungsmethode recordscheint recht einfach zu sein:

api_blueprint = Blueprint('xxx.api',  __name__, None)
api_blueprint.config = {}

@api_blueprint.record
def record_params(setup_state):
  app = setup_state.app
  api_blueprint.config = dict([(key,value) for (key,value) in app.config.iteritems()])
Ashalynd
quelle
1
Für Python 3 verwenden Sie: app.config.items () anstelle von app.config.iteritems ()
DhoTjai
1
Hallo, muss ich record_params aufrufen oder registrieren? Ich habe es versucht, aber es hat nicht funktioniert. Vielen Dank.
Mrblue
Wenn Sie Zugriff auf eine App benötigen (z. B. die Konfiguration zum Einrichten der Blaupause), ist dies großartig!
Peter Lada
12

Um auf der Antwort von tbicr aufzubauen , ist hier ein Beispiel, das das registerMethodenbeispiel überschreibt :

from flask import Blueprint

auth = None

class RegisteringExampleBlueprint(Blueprint):
    def register(self, app, options, first_registration=False):
        global auth

        config = app.config
        client_id = config.get('CLIENT_ID')
        client_secret = config.get('CLIENT_SECRET')
        scope = config.get('SCOPE')
        callback = config.get('CALLBACK')

        auth = OauthAdapter(client_id, client_secret, scope, callback)

        super(RegisteringExampleBlueprint,
              self).register(app, options, first_registration)

the_blueprint = RegisteringExampleBlueprint('example', __name__)

Und ein Beispiel mit dem recordDekorateur :

from flask import Blueprint
from api import api_blueprint as api

auth = None

# Note there's also a record_once decorator
@api.record
def record_auth(setup_state):
    global auth

    config = setup_state.app.config
    client_id = config.get('CLIENT_ID')
    client_secret = config.get('CLIENT_SECRET')
    scope = config.get('SCOPE')
    callback = config.get('CALLBACK')

    auth = OauthAdapter(client_id, client_secret, scope, callback)
Kyle James Walker
quelle
'@ api.record' funktioniert bei mir nicht ,. Aus welchem ​​Namespace stammt 'api'?
Tim Richardson
Sorry, habe das nicht aus der Zeile in der Frage kopiertfrom api import api_blueprint as api
Kyle James Walker
4

Der current_appAnsatz ist in Ordnung, aber Sie müssen einen Anforderungskontext haben. Wenn Sie keine haben (z. B. Vorarbeiten wie Tests), sollten Sie diese besser platzieren

with app.test_request_context('/'):

vor diesem current_appAnruf.

Sie werden RuntimeError: working outside of application contextstattdessen haben.

Ben Usman
quelle
3
Was ist, wenn die App in einer Fabrik erstellt wird und daher 'App' (oder wie auch immer man die Kolben-App nennt) nicht zum Importieren verfügbar ist? Innerhalb von Anfragen ist dies kein Problem, da bei Anfragen ein App-Kontext vorhanden ist, beim Definieren von Teilen außerhalb der Anforderungslogik jedoch eine App-Konfiguration erforderlich ist. Wie kann man auf die App-Konfiguration zugreifen, wenn Sie die App nicht zum Erstellen des Kontexts verwenden können?
RobertoCuba
3

Sie müssen entweder die appHauptvariable (oder wie auch immer Sie sie genannt haben) importieren, die zurückgegeben wird von Flask():

from someplace import app
app.config.get('CLIENT_ID')

Oder tun Sie dies innerhalb einer Anfrage:

@api.route('/authorisation_url')
def authorisation_url():
    client_id = current_app.config.get('CLIENT_ID')
    url = auth.get_authorisation_url()
    return str(url)
Daniel Chatfield
quelle
4
Ja, ich wollte keines von beiden machen. Der erste ist das Erstellen von Querverweisen und der zweite Ansatz ist nicht trocken.
Chirdeep Tomar
2
@ChirdeepTomar Wenn der erste Ansatz darin besteht, zirkuläre Importe zu erstellen (die die App beschädigen), stimmt etwas nicht mit der Struktur Ihrer App.
Daniel Chatfield
13
@ DanielChatfield das ist einfach nicht wahr. Das App-Objekt ist das Objekt, das Blaupausen registriert. Wenn Sie vorschlagen, dass der Entwurf dann korrekt ist, um das App-Objekt zu importieren, entsteht immer eine zirkuläre Abhängigkeit. Weitere Antworten finden Sie in den richtigen Antworten.
Sholsapp
@sholsapp Ich weiß, dass ein zirkulärer Import erstellt wird (genau wie in den Flask- Dokumenten: flask.pocoo.org/docs/patterns/packages ). Ich sagte, wenn ein zirkulärer Import erstellt wurde , der die App beschädigte .
Daniel Chatfield
1

Sie können den Entwurf auch in eine Funktion einschließen und das appals Argument übergeben:

Entwurf:

def get_blueprint(app):
    bp = Blueprint()
    return bp

Main:

from . import my_blueprint
app.register_blueprint(my_blueprint.get_blueprint(app))
Georg Schölly
quelle
Ich habe es versucht, aber ich habe einen "internen Serverfehler" erhalten.
MD004
Irgendwelche Nachteile bei diesem Ansatz?
Tuukka Mustonen
@ Tuukka: Ich erinnere mich an keine besonderen Nachteile, es ist ein bisschen zu lange her, seit ich es benutzt habe. Die flask.current_appVerwendung des Entwurfs in mehreren Apps bietet möglicherweise einige Vorteile . Ich würde vorschlagen, wenn dieser Ansatz Ihre Probleme löst, um ihn zu verwenden, erzwingt Flask keinen bestimmten Ansatz.
Georg Schölly