如何在Flask配置中存储数据库URI以适配原生SQLAlchemy?
Flask + 原生SQLAlchemy 访问配置时的应用上下文错误解决
我使用Flask搭配原生SQLAlchemy(而非flask-sqlalchemy),尝试从数据库代码中访问Flask配置时,系统提示处于应用上下文之外,推测是应用未完全初始化导致的问题。
我的代码
app.py
from flask import Flask from root.views.calibration_views import calibration nwm_app = Flask(__name__) nwm_app.config.from_pyfile('myConfig.cfg') print('config', nwm_app.config)
database.py(被calibration_views导入)
from sqlalchemy import URL, create_engine from sqlalchemy.orm import sessionmaker from flask import current_app as nwm_app url = URL.create( drivername="postgresql", username="postgres", password="postgres", host="localhost", database="flask_test" ) engine = create_engine(url, echo=True) with nwm_app.app_context(): print('config', nwm_app.config) Session = sessionmaker(bind=engine)
报错信息
RuntimeError: Working outside of application context. This typically means that you attempted to use functionality that was needed. The current application. To solve this, set up an application context. With app.app_context(). See the documentation for more information.
我尝试用current_app获取配置以避免循环导入错误,但仍出现上述报错,用nwm_app.app_context()修复也无效,目前纠结是继续用Flask配置还是改用常规Python方式加载单独配置文件。
问题根源
- 模块级代码会在导入时立即执行,你在
database.py里导入current_app后直接尝试创建应用上下文,但此时app.py里的应用实例还没完成初始化(因为app.py先导入了calibration_views,后者又导入database.py,这时候Flask配置还没加载,current_app也没绑定到任何应用实例)。 - 用
current_app的前提是当前处于有效的应用上下文内,而模块导入阶段根本不存在这个上下文。
解决方案
方案一:延迟初始化SQLAlchemy组件
把数据库相关的初始化逻辑封装成函数,等到Flask应用上下文建立后再调用:
修改database.py:
from sqlalchemy import URL, create_engine from sqlalchemy.orm import sessionmaker from flask import current_app # 先定义空的全局变量 engine = None Session = None def init_db(): global engine, Session # 从Flask配置中读取数据库参数 db_config = current_app.config url = URL.create( drivername="postgresql", username=db_config.get('DB_USER'), password=db_config.get('DB_PASS'), host=db_config.get('DB_HOST'), database=db_config.get('DB_NAME') ) engine = create_engine(url, echo=True) Session = sessionmaker(bind=engine)
修改app.py,在加载配置后初始化数据库:
from flask import Flask from root.views.calibration_views import calibration from root.database import init_db nwm_app = Flask(__name__) nwm_app.config.from_pyfile('myConfig.cfg') print('config', nwm_app.config) # 在应用上下文内初始化数据库 with nwm_app.app_context(): init_db()
这样就能确保访问current_app时,应用上下文已经存在,配置也加载完成。
方案二:使用独立Python配置文件
如果不需要和Flask配置联动,可以单独创建配置文件,脱离Flask上下文:
创建config.py:
DB_USER = "postgres" DB_PASS = "postgres" DB_HOST = "localhost" DB_NAME = "flask_test"
修改database.py:
from sqlalchemy import URL, create_engine from sqlalchemy.orm import sessionmaker from root.config import DB_USER, DB_PASS, DB_HOST, DB_NAME url = URL.create( drivername="postgresql", username=DB_USER, password=DB_PASS, host=DB_HOST, database=DB_NAME ) engine = create_engine(url, echo=True) Session = sessionmaker(bind=engine)
这种方式无需考虑Flask上下文问题,实现更简单。
内容的提问来源于stack exchange,提问作者Peter Kronenberg
相关产品推荐
相关产品推荐

