2013-10-17 3 views
53

Sto rivedendo l'applicazione Flask sparpagliando i modelli, i blueprints ma sto avendo un errore di runtime.Quando si diffondono i modelli di flask, RuntimeError: "l'applicazione non registrata su db" è stata sollevata

def create_app(): 
    app = flask.Flask("app") 
    app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite://' 
    app.register_blueprint(api) 
    db.init_app(app) 
    db.create_all() 
    return app 

Ho il seguente problema (il progetto di esempio sono ospitati qui: https://github.com/chfw/sample):

Traceback (most recent call last): 
    File "application.py", line 17, in <module> 
    app = create_app() 
    File "application.py", line 12, in create_app 
    db.create_all() 
    File "\AppData\Roaming\Python\Python27\site-packages\flask_sqlalchemy\__init__.py", line 856, in create_all 
    self._execute_for_all_tables(app, bind, 'create_all') 
    File "\AppData\Roaming\Python\Python27\site-packages\flask_sqlalchemy\__init__.py", line 836, in _execute_for_all_tables 
    app = self.get_app(app) 
    File "\AppData\Roaming\Python\Python27\site-packages\flask_sqlalchemy\__init__.py", line 809, in get_app 
    raise RuntimeError('application not registered on db 
      'RuntimeError: application not registered on db 
      instance and no application bound to current context 

ho fatto una ricerca su questo argomento. La ri-factoring si suggerisce qui:

Flask-SQLAlchemy import/context issue

Lo stesso problema è stato sollevato qui:

http://flask.pocoo.org/mailinglist/archive/2010/8/30/sqlalchemy-init-app-problem/#b1c3beb68573efef4d6e571ebc68fa0b

E il filo sopra (2010) hanno suggerito un hack come questo:

app.register_blueprint(api) 
    db.app=app #<------------<< 
    db.init_app(app) 

Qualcuno sa come farlo correttamente? come l'hai risolto?

Grazie

risposta

121

Questo ha a che fare con la boccetta di application context. Quando è inizializzato con db.init_app(app), Flask-SQLAlchemy non sa quale app è l'app "corrente" (ricorda che Flask consente lo multiple apps nello stesso interprete). Potresti avere più app che utilizzano la stessa istanza SQLAlchemy nello stesso processo e Flask-SQLAlchemy avrebbe bisogno di sapere qual è quella "corrente" (a causa della natura di Flask del context local di Flask).

Se è necessario eseguire questa operazione durante il runtime, è necessario indicare esplicitamente quale app è l'app "corrente" per tutte le chiamate. È possibile farlo modificando il codice per utilizzare un with app.app_context() blocco:

def create_app(): 
    app = flask.Flask("app") 
    app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite://' 
    app.register_blueprint(api) 
    db.init_app(app) 
    with app.app_context(): 
     # Extensions like Flask-SQLAlchemy now know what the "current" app 
     # is while within this block. Therefore, you can now run........ 
     db.create_all() 

    return app 

Se si sta scrivendo uno script autonomo che ha bisogno del contesto applicazione, è possibile spingere il contesto all'inizio invece di mettere tutto in un blocco with.

create_app().app_context().push() 

Se si scrive un comando per Flask di cli il comando avrà automaticamente accesso al contesto.

+0

Giusto, questo funziona. Ora non ho le eccezioni. Ma il prossimo è: "applicazione non registrata su db" -> RuntimeError: applicazione non registrata su istanza db e nessuna applicazione legata al contesto corrente – chfw

+2

Qual è la differenza qui e l'aggiunta di db.app = app? – user805981

+1

@ user805981 In questo modo potrebbe funzionare, ma non è molto pulito. Innanzitutto, si interrompe l'incapsulamento, poiché l'attributo 'app' su SQLAlchemy non è progettato per essere pubblico. Questo oggetto potrebbe aver bisogno di fare altre cose quando sta cambiando l'app che sta usando. In secondo luogo, 'app_context' fa molto di più che cambiare Flask-SQLAlchemy; in realtà dice a Flask di cambiare l'app corrente. Quindi, potresti aver bisogno di questo per fare cose con varie API Flask, o lavorare con l'app con tutte le tue estensioni Flask. –

5

La risposta di Mark è stata ottima e mi ha aiutato molto. Tuttavia, un altro modo per avvicinarsi a questo è eseguire il codice che si basa sul contesto dell'app in una funzione decorata con @ app.before_first_request. Vedere http://flask.pocoo.org/docs/0.10/appcontext/ per ulteriori informazioni. Questo è in effetti il ​​modo in cui ho finito per farlo, soprattutto perché volevo essere in grado di chiamare il codice di inizializzazione al di fuori del pallone, che gestisco in questo modo.

Nel mio caso, voglio essere in grado di testare i modelli SQLAlchemy come semplici modelli SQLAlchemy senza Flask-SQLAlchemy, sebbene il db nel codice sottostante sia semplicemente un (Flask) SQLAlchemy db.

@app.before_first_request 
def recreate_test_databases(engine = None, session = None): 
    if engine == None: 
    engine = db.engine 
    if session == None: 
    session = db.session 

    Base.metadata.drop_all(bind=engine) 
    Base.metadata.create_all(bind=engine) 
    # Additional setup code 
+0

John, potresti unire la risposta duplicata a questa (dato che questa ha upvotes) e cancellare l'altra? – KobeJohn

+0

Eliminato, nessuna unione necessaria. –

+0

Qualche suggerimento per un file che dovrebbe contenere le funzioni '@ app.before_first_request'? – AlexLordThorsen

Problemi correlati