【问题标题】:How to initialize a Postgresql database in a Flask app with SQLAlchemy如何使用 SQLAlchemy 在 Flask 应用程序中初始化 Postgresql 数据库
【发布时间】:2022-01-12 15:42:06
【问题描述】:

Flask tutorial(以及许多other tutorialsout there)表明enginedb_sessionBasedeclarative_metadata 的一个实例)都是在导入时创建的。

这会产生一些问题,其中一个是 DB 的 URI 被硬编码在代码中并且只评估一次。 一种解决方案是将这些调用包装在接受app 作为参数的函数中,这就是我所做的。请注意 - 每次调用都会将结果缓存在 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                                

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)

气味当然是我在导入和创建所有模型时必须经历的过程。 上面代码的原因是,在单元测试的时候,每次测试都会调用一次init_db(在setup()中,作为suggested in the same tutorial),但是导入只会在第一次执行,create_all会因此只在那个时候工作。

不仅如此,现在在应用程序期间共享会话,我在参数化负单元测试(即预期某种失败的参数化单元测试)中遇到问题:测试的第一个实例将触发失败(例如登录失败,参见test_login_validate_input in the tutorial)并正确退出,而所有后续将提前退出,因为db_session 应首先回滚。显然数据库初始化有问题。

什么是初始化数据库的正确方法(TM)?

【问题讨论】:

    标签: python postgresql flask sqlalchemy


    【解决方案1】:

    我最终决定重构应用程序,使其使用Flask-SQLAlchemy

    简而言之,应用程序现在执行以下操作:

    from flask_sqlalchemy import SQLAlchemy
    
    db = SQLAlchemy()
    
    def create_app():
        app = Flask(__name__)
        db.init_app(app)
        # ...
    

    事后看来,这绝对是一种更清洁的方法。 一开始让我很反感的是tutorial 的这个条目(粗体是我的):

    因为 SQLAlchemy 是一个通用的数据库抽象层和对象关系映射器,需要一些配置工作,所以有一个 Flask 扩展可以为您处理。 如果您想快速入门,建议您这样做

    我以某种方式将其解读为“使用 Flask-SQLAlchemy 扩展可以让您走捷径,但您可能最终会为此付出代价”。

    这是非常早期的阶段,但到目前为止,在使用所述扩展的灵活性方面还没有付出任何代价。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-01-24
      • 2013-03-24
      • 2023-01-27
      • 2021-07-09
      • 1970-01-01
      • 2020-09-25
      • 2021-10-07
      • 2018-10-21
      相关资源
      最近更新 更多