Подтвердить что ты не робот

При рассеянии фляжных моделей RuntimeError: "приложение, не зарегистрированное на db", было поднято

Я повторно факторизую приложение 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)

Кто-нибудь знал, как это сделать правильно? Как вы его решили?

Спасибо

4b9b3361

Ответ 1

Это связано с Flask контекстом приложения. Когда инициализируется с помощью db.init_app(app), Flask-SQLAlchemy не знает, какое приложение является "текущим" приложением (помните, Flask позволяет несколько приложений в том же интерпретаторе). У вас может быть несколько приложений, использующих один и тот же экземпляр SQLAlchemy в одном и том же процессе, и Flask-SQLAlchemy должен знать, что является "текущим" (из-за Flask context local природа всего).

Если вам нужно сделать это во время выполнения, вы должны явно указать, какое приложение является "текущим" приложением для всех вызовов. Вы можете сделать это, изменив свой код, чтобы сделать следующее:

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

Если вы пишете автономный script, который нуждается в контексте приложения, вы можете использовать контекст в начале, а не помещать все в блок with.

create_app().app_context().push()

Если вы напишете команду для Flask cli, то команда автоматически получит доступ к контексту.

Ответ 2

Отметить ответ было замечательно, и это очень помогло мне. Однако другой способ приблизиться к этому - запустить код, который опирается на контекст приложения в функции, украшенной @app.before_first_request. Подробнее см. http://flask.pocoo.org/docs/0.10/appcontext/. Это на самом деле то, как я это сделал, во многом потому, что я хотел иметь возможность вызвать код инициализации вне фляги, который я обрабатываю таким образом.

В моем случае я хочу иметь возможность тестировать модели SQLAlchemy как простые модели SQLAlchemy без Flask-SQLAlchemy, хотя db в коде ниже - это просто (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