Jak uzyskać dostęp do app.config w planie?

115

Próbuję uzyskać dostęp do konfiguracji aplikacji wewnątrz planu, authorisation.pyktóry w pakiecie API. Inicjalizuję plan, w __init__.pyktórym jest używany 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)

Otrzymuję RuntimeError: praca poza kontekstem aplikacji

Rozumiem, dlaczego tak jest, ale jaki jest prawidłowy sposób dostępu do tych ustawień konfiguracyjnych?

---- Aktualizacja ---- Tymczasowo zrobiłem to.

@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
źródło

Odpowiedzi:

133

Użyj flask.current_appzamiast appw widoku planu.

from flask import current_app

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

Serwer current_appproxy jest dostępny tylko w kontekście żądania .

weihuang
źródło
25
Należy pamiętać, że current_appserwer proxy jest dostępny tylko w kontekście żądania.
wrzesień
1
@sephr Jakieś wskazówki, jak uzyskać dostęp do kontekstu żądania z innych miejsc (bez przekazywania go jako parametru, ale jako pewnego rodzaju parametru globalnego)?
carkod
21

recordMetoda przeładowania wydaje się dość prosta:

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
źródło
1
W przypadku Pythona 3 użyj: app.config.items () zamiast app.config.iteritems ()
DhoTjai
1
Cześć, czy muszę wywołać lub zarejestrować parametr record_params, próbowałem, ale to nie zadziałało. Wielkie dzięki.
mrblue
Jeśli potrzebujesz dostępu do aplikacji (na przykład pobrania konfiguracji do USTAWIENIA planu), to świetnie!
Peter Lada
12

Aby zbudować na odpowiedzi tbicr , oto przykład zastępujący przykład registermetody :

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

I przykład z wykorzystaniem recorddekoratora :

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
źródło
„@ api.record” nie działa dla mnie,. Z jakiej przestrzeni nazw pochodzi „API”?
Tim Richardson
Niestety, nie skopiowałem tego z linii w pytaniufrom api import api_blueprint as api
Kyle James Walker
4

current_appPodejście jest w porządku, ale trzeba mieć jakiś kontekst żądania. Jeśli go nie masz (jakieś prace przygotowawcze, takie jak testowanie, np.), Lepiej to miejsce

with app.test_request_context('/'):

przed tym current_appwezwaniem.

Zamiast tego będziesz miał RuntimeError: working outside of application context.

Ben Usman
źródło
3
A co z sytuacją, gdy aplikacja jest tworzona w fabryce i dlatego „aplikacja” (lub jakkolwiek nazywa się ją aplikacją kolby) nie jest dostępna do zaimportowania? Żądania wewnętrzne nie stanowią problemu, ponieważ podczas żądań występuje kontekst aplikacji, ale podczas definiowania części poza logiką żądania, które wymagają konfiguracji aplikacji. jak można uzyskać dostęp do konfiguracji aplikacji, jeśli nie można użyć aplikacji do utworzenia kontekstu?
RobertoCuba
3

Musisz albo zaimportować główną appzmienną (lub jakkolwiek ją nazwałeś), która jest zwracana przez Flask():

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

Lub zrób to z poziomu żądania:

@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
źródło
4
Tak, nie chciałem robić żadnego z tych dwóch. Pierwszym jest tworzenie odniesień, a drugie podejście nie jest SUCHE.
Chirdeep Tomar
2
@ChirdeepTomar Jeśli pierwsze podejście polega na tworzeniu cyklicznych importów (które powodują uszkodzenie aplikacji), oznacza to, że jest coś nie tak ze strukturą Twojej aplikacji.
Daniel Chatfield
13
@DanielChatfield to po prostu nieprawda. Obiekt aplikacji to obiekt, który rejestruje plany. Sugerowanie, że plan jest prawidłowy, a następnie zaimportowanie obiektu aplikacji zawsze spowoduje zależność cykliczną. Zobacz inne odpowiedzi, aby poznać właściwą strategię.
sholsapp
@sholsapp Wiem, że utworzy cykliczny import (tak jak to robi w dokumentach flask: flask.pocoo.org/docs/patterns/packages ), powiedziałem, że utworzy cykliczny import, który zepsuł aplikację .
Daniel Chatfield,
1

Możesz również zawinąć schemat w funkcję i przekazać appjako argument:

Projekt:

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

Główny:

from . import my_blueprint
app.register_blueprint(my_blueprint.get_blueprint(app))
Georg Schölly
źródło
Próbowałem tego, ale otrzymałem komunikat „Wewnętrzny błąd serwera”.
MD004,
Jakieś wady tego podejścia?
Tuukka Mustonen
@Tuukka: Nie pamiętam żadnych szczególnych wad, minęło trochę czasu, odkąd go używałem. flask.current_appKorzystanie z planu w wielu aplikacjach może mieć pewne zalety . Sugerowałbym, że jeśli to podejście rozwiązuje Twoje problemy, to Flask nie wymusza określonego podejścia.
Georg Schölly,