70

モデルやブループリントを分散させて Flask アプリケーションをリファクタリングしていますが、ランタイム エラーが発生しています。

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

次の問題があります (サンプル プロジェクトはここでホストされています: 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

私はこのトピックについて調査を行いました。リファクタリングはここで提案されています:

Flask-SQLAlchemy のインポート/コンテキストの問題

同じ問題がここで提起されました:

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

そして、上記のスレッド (2010) は、次のようなハックを提案しました:

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

誰かがこれを適切に行う方法を知っていましたか? どのように解決しましたか?

ありがとう

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/を参照してください。実際、それが私が最終的にそれを行った方法です。主に、初期化コードをフラスコの外部でも呼び出すことができるようにしたかったためです。これは、この方法で処理します。

私の場合、Flask-SQLAlchemy を使用せずに 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 に答える