首页 文章

如何使用flask,SQLAlchemy和declarative_base避免硬编码数据库路径

提问于
浏览
1

Flask-SQLAlchemy建议用于设置数据库连接的Declarative模式 . 该示例对单个数据库路径进行硬编码,似乎我应该避免这种情况,以便我可以为单元测试,本地开发以及最终生成配置不同的数据库 .

这是他们的database.py:

from sqlalchemy import create_engine
from sqlalchemy.orm import scoped_session, sessionmaker
from sqlalchemy.ext.declarative import declarative_base

engine = create_engine('sqlite:////tmp/test.db', convert_unicode=True)
db_session = scoped_session(sessionmaker(autocommit=False,
                                     autoflush=False,
                                     bind=engine))
Base = declarative_base()
Base.query = db_session.query_property()

def init_db():
    # import all modules here that might define models so that
    # they will be registered properly on the metadata.  Otherwise
    # you will have to import them first before calling init_db()
    import yourapplication.models
    Base.metadata.create_all(bind=engine)

但我无法弄清楚如何避免硬编码这个数据库路径 .

环境变量:

我可以用环境变量替换 sqlite:///.... 路径 . 但这需要某种方式让 pytest 与一组环境变量运行,而 flask run 使用不同的集合 . 我'd much rather have my unit tests keep track of their own temporary database.[2] I'也喜欢 create_app() ,它创建了Flask应用程序来获取一个配置变量的数据库路径 .

在应用程序上下文中导入database.py

我以为我可以用 current_app.config['DB'] 替换数据库路径,并在 with app.app_context() 中导入数据库 . 但Model类需要导入Base,我可以在应用程序上下文之外重新加载,并抛出运行时错误 .

那么在单元测试的烧瓶应用程序中使用declarative_base的正确方法是什么?

谢谢你的帮助!

[2]:如果这就是我应该做的,那么我就能忍受它 . 但是当我使用自己的配置变量配置烧瓶应用程序时,在那里使用env变量似乎很麻烦 .

1 回答

  • 1

    我已经解决了我的问题 . 而不是使用declarative_base类工厂:

    database.py:

    engine="someengine"
    db_session=[make a session here]
    Base = declarative_base()
    Base.query = db_session.query
    

    让我的模型导入Base,

    我只是按照模式here . 在database.py中,我创建了一个哑数据库

    db = SQLAlchemy()
    

    然后在 init .py中,在create_app app工厂中,我可以使用app config变量初始化应用程序并使用app初始化数据库 . *

    db.init_app(app)
    with app.app_context():
        import site.models
        db.create_all()
    

    模型继承自database.py的 db.Model 类 .

    from site.database import db
    class MyModel(db.Model)
    

    我可以通过在一个fixture中包装测试来访问pytest测试中的数据库:

    @pytest.fixture
    def app():
        app = create_app({[testing config]}
        with app.app_context():
            g.db = db
            yield app
            g.db.session.remove()
            g.db.drop_all()
    

    这对我来说很有用 . 那就是说,如果你认为我做错了什么,请告诉我!

    *我认为SQLAlchemy对象一旦用 init_app 初始化,就会存储指向只存在's an active application context? Is that right? That'为什么只是调用 db 没有连接到apps数据库但在应用程序上下文中调用 db 的值的指针 .

相关问题