Flask-SQLAlchemy建议使用Declarative模式来建立数据库连接。该示例对单个数据库路径进行硬编码,似乎应该避免这种情况,以便可以为单元测试,本地开发以及最终生产配置不同的数据库。
这是他们的数据库。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
使用另一组环境变量。我宁愿让单元测试跟踪自己的临时数据库。[2]我还希望创建create_app()
的Flask应用程序采用配置变量的数据库路径。
我认为我可以用current_app.config['DB']
替换数据库路径,并在with app.app_context()
内导入数据库。但是Model类需要导入Base,而我不能在应用程序上下文中将Base子类化。因此,当模型被加载时,它们被加载到应用程序上下文之外,这会引发运行时错误。
感谢您的帮助!
[2]:如果那是我应该做的,那么我可以接受。但是当我也使用自己的配置变量配置flask应用程序时,在其中使用env vars似乎很麻烦。
答案 0 :(得分: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()
然后在create_app应用程序工厂的 init .py中,我可以使用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)
我可以通过将测试包装在夹具中来访问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
初始化后,就会存储指向仅在存在活动应用程序上下文时才存在的值的指针?那正确吗?这就是为什么仅调用db
不会连接到应用程序数据库,而是在应用程序上下文中调用db
的原因。