简体   繁体   English

如何使用 SQLAlchemy 在 Flask 应用程序中初始化 Postgresql 数据库

[英]How to initialize a Postgresql database in a Flask app with SQLAlchemy

TheFlask tutorial (and many other tutorials out there ) suggests that the engine , the db_session and the Base (an instance of declarative_metadata ) are all created at import-time. Flask 教程(以及许多其他教程)建议enginedb_sessionBasedb_session的一个declarative_metadata )都是在导入时创建的。

This creates some problems, one being, that the URI of the DB is hardcoded in the code and evaluated only once.这会产生一些问题,其中一个是 DB 的 URI 被硬编码在代码中并且只评估一次。 One solution is to wrap these calls in functions that accept the app as a parameter, which is what I've done.一种解决方案是将这些调用包装在接受app作为参数的函数中,这就是我所做的。 Mind you - each call caches the result in app.config :请注意 - 每个调用都将结果缓存在app.config中:

def get_engine(app):                                                                           
    """Return the engine connected to the database URI in the config file.
    Store it in the config for later use.
    """
    engine = app.config.setdefault(
        'DB_ENGINE', create_engine(app.config['DATABASE_URI'](), echo=True))
    return engine                                                                              
                                                                                               
def get_session(app):                                                                          
    """Return the DB session for the database in use
    Store it in the config for later use.
    """                          
    engine = get_engine(app)
    db_session = app.config.setdefault(
        'DB_SESSION', scoped_session(sessionmaker(
            autocommit=False, autoflush=False, bind=engine)))
    return db_session
                                                                                               
def get_base(app):                     
    """Return the declarative base to use in DB models.
    Store it in the config for later use.
    """                                                                                        
    Base = app.config.setdefault('DB_BASE', declarative_base())
    Base.query = get_session(app).query_property()
    return Base                                

In init_db , I call all those functions, but there's still code smell:init_db中,我调用了所有这些函数,但仍然有代码异味:

def init_db(app):
    """Initialise the database"""
    create_db(app)
    engine = get_engine(app)
    db_session = get_session(app)
    base = get_base(app)

    if not app.config['TESTING']:
        import flaskr.models
    else:
        if 'flaskr.models' not in sys.modules:
            import flaskr.models
        else:
            import flaskr.models
            importlib.reload(flaskr.models)

    base.metadata.create_all(bind=engine)

The smell is of course the hoops I have to go through to import and create all models.气味当然是我必须通过 go 导入和创建所有模型的箍。 The reason for the code above is that, when unit testing, init_db is called once for each test (in setup() , as suggested in the same tutorial ), but the import will only be performed the first time, and create_all will therefore work only that time.上面代码的原因是,在单元测试时,每次测试都会调用一次init_db (在setup()中,如同一教程中所建议的那样),但导入只会在第一次执行,因此create_all将起作用只有那个时候。

Not only that, now with a session shared for the duration of the app, I have problems in parametrized negative unit tests (that is, parametrized unit tests that expect some sort of failures): the first instance of the test will trigger a failure (eg login failure, see test_login_validate_input in the tutorial ) and exit correctly, while all subsequent will bail out early because the db_session should be rolled back first.不仅如此,现在有了在应用程序期间共享的 session,我在参数化负单元测试(即预期某种失败的参数化单元测试)中遇到问题:测试的第一个实例将触发失败(例如登录失败,请参阅教程中的test_login_validate_input )并正确退出,而所有后续将提前退出,因为应该首先回滚db_session Clearly there's something wrong with the DB initialization.显然数据库初始化有问题。

What is the Right Way(TM) to initialize the database?初始化数据库的正确方法是什么?

I have eventually decided to refactor the app so that it uses Flask-SQLAlchemy .我最终决定重构应用程序,以便它使用Flask-SQLAlchemy

In short, the app now does something like this:简而言之,该应用程序现在执行以下操作:

from flask_sqlalchemy import SQLAlchemy

db = SQLAlchemy()

def create_app():
    app = Flask(__name__)
    db.init_app(app)
    # ...

With the benefit of hindsight, it's definitely a cleaner approach.事后看来,这绝对是一种更清洁的方法。 What put me off at the start was this entry from the tutorial (bold is mine):一开始让我失望的是教程中的这个条目(粗体是我的):

Because SQLAlchemy is a common database abstraction layer and object relational mapper that requires a little bit of configuration effort, there is a Flask extension that handles that for you.因为 SQLAlchemy 是一个通用的数据库抽象层,而 object 关系映射器需要一些配置工作,所以有一个 Flask 扩展可以为您处理。 This is recommended if you want to get started quickly .如果您想快速入门,建议您这样做

Which I somehow read as "Using the Flask-SQLAlchemy extension will allow you to cut some corners, which you'll probably end up paying for later".我以某种方式将其读作“使用 Flask-SQLAlchemy 扩展将允许您走捷径,您可能最终会为此付出代价”。

It's very early stages, but so far no price to pay in terms of flexibility for using said extension.这是非常早期的阶段,但到目前为止,在使用所述扩展的灵活性方面还没有付出任何代价。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何使用 Flask / SQLalchemy / Alembic 初始化数据库表? - How can I initialize a database table with Flask / SQLalchemy / Alembic? 如何使用Flask-sqlalchemy.exc.ProgrammingError将数据插入Postgresql数据库? - How to insert data to postgresql database with flask - sqlalchemy.exc.ProgrammingError? 泄漏的数据库连接:PostgreSQL、SQLAlchemy、Flask - Leaking database connections: PostgreSQL, SQLAlchemy, Flask 如何使用 sqlalchemy 在 flask 应用程序的现有数据库中添加新表? - How to add new table in existing database of flask app using sqlalchemy? 如何在 Google App Engine 上为 postgresql 设置 flask-admin 和 flask-sqlalchemy? - How to setup flask-admin and flask-sqlalchemy for postgresql on Google App Engine? Google App Engine-Flask-SQLAlchemy-不一致的数据库 - Google App Engine - Flask - SQLAlchemy - Inconsistent Database 如何在 SQLAlchemy(特别是 Flask-SQLAlchemy)中使用 PostgreSQL 扩展? - How to use PostgreSQL extensions in SQLAlchemy (specifically Flask-SQLAlchemy)? 从单独的烧瓶应用程序访问使用烧瓶 sqlalchemy 创建的数据库 - Accessing a database created with flask-sqlalchemy from a separate flask app sqlalchemy 不初始化数据库 - sqlalchemy does not initialize the database 如何从 sqlalchemy 数据库返回 flask 中的文件 - How to return a file in flask from sqlalchemy database
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM