70

I am re-factoring my Flask application by scattering the models, blueprints but I am having a runtime error.

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

I have the following problem(the sample project are hosted here: 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

I did a research on this topic. The re-factoring is suggested here:

Flask-SQLAlchemy import/context issue

The same problem was raised here:

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

And the above thread(2010) suggested a hack like this:

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

Did anyone know how to do this properly? How did you solve it?

Thanks

4

2 回答 2

142

这与 Flask 的应用程序上下文有关。当用 初始化时db.init_app(app),Flask-SQLAlchemy 不知道哪个应用程序是“当前”应用程序(请记住,Flask 允许在同一个解释器中使用多个应用程序)。您可以SQLAlchemy在同一个进程中使用同一个实例的多个应用程序,并且 Flask-SQLAlchemy 需要知道哪个是“当前”的应用程序(由于 Flask 的上下文本地特性)。

如果您需要在运行时执行此操作,则必须明确说明哪个应用程序是所有调用的“当前”应用程序。您可以通过更改代码以使用with app.app_context()块来做到这一点:

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

如果您正在编写需要应用程序上下文的独立脚本,则可以在开始时推送上下文,而不是将所有内容都放在一个with块中。

create_app().app_context().push()

如果您为 Flask 的cli编写命令,该命令将自动访问上下文。

于 2013-10-17T21:58:32.027 回答
7

马克的回答很棒,对我帮助很大。但是,解决此问题的另一种方法是在使用@app.before_first_request 修饰的函数中运行依赖于应用程序上下文的代码。有关更多信息,请参阅http://flask.pocoo.org/docs/0.10/appcontext/。事实上,我最终就是这样做的,主要是因为我希望能够在烧瓶之外调用初始化代码,我以这种方式处理。

就我而言,我希望能够将 SQLAlchemy 模型作为没有 Flask-SQLAlchemy 的普通 SQLAlchemy 模型进行测试,尽管下面代码中的数据库只是一个(Flask)SQLAlchemy 数据库。

@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
于 2016-02-07T22:47:35.367 回答