When scattering Flask Models, RuntimeError: 'application not registered on db' was raised
This has to do with Flask's application context. When initialized with db.init_app(app)
, Flask-SQLAlchemy doesn't know which app is the "current" app (remember, Flask allows for multiple apps in the same interpreter). You could have multiple apps using the same SQLAlchemy
instance in the same process, and Flask-SQLAlchemy would need to know which is the "current" one (due to Flask's context local nature of everything).
If you need to do this during runtime, you must explicitly say which app is the "current" app for all calls. You can do this by changing your code to use a with app.app_context()
block:
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
If you are writing a standalone script that needs the app context, you can push the context at the beginning rather than putting everything in a with
block.
create_app().app_context().push()
If you write a command for Flask's cli the command will automatically have access to the context.
Mark's answer was great and it helped me a lot. However, another way to approach this is to run the code that relies on the app context in a function decorated with @app.before_first_request. See http://flask.pocoo.org/docs/0.10/appcontext/ for more information. That's in fact how I ended up doing it, largely because I wanted to be able to call the initialization code outside of flask as well, which I handle this way.
In my case I want to be able to test SQLAlchemy models as plain SQLAlchemy models without Flask-SQLAlchemy, though the db in the code below is simply a (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