python Flask项目使用SQLalchemy连接数据库时,出现RuntimeError:Working outside of application context.的解决过程记录
作者:mmseoamin日期:2023-12-14

一、问题出现

在使用python的Flask框架跟着教程编写项目时,我跟着教程使用了三个文件来组织,分别是main.py(主程序),module.py(数据库模型),controller.py(蓝图模块程序,用Blueprint衔接)

在主程序中,创建app、SQLalchemy实例对象db并将二者绑定

app = Flask(__name__, static_url_path='/')
# 配置app参数
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://root:password@localhost:3306/ayangnote?charset=utf8'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False  # True跟踪数据库的修改,及时发送信号
# 实例化db对象,绑定flask的app
db = SQLalchemy(app)

在module.py中,导入主程序中的db和app,创建子类Users作为查询表,并定义数据库查询的方法

from main import db # 直接引用main模块中的全局变量
    
class Users(db.Model):
    __table__ = Table('users', db.metadata, autoload_with=db.engine, mysql_bind=db.engine)
    def find_user_by_id(self, userid):
        row = db.session.query(Users).filter(Users.userid == userid).first()
        return row
    def find_user_by_id2(self, userid):
        row = Users.query.filter(Users.userid == userid).first()
        return row

controller.py与主程序通过Blueprint衔接,并且创建查询接口和指定操作

但我写完后,运行起来报错RuntimeError: Working outside of application context.表示缺少上下文

二、试图修改

在查询相关解决方案后,我试图理解了一下Flask框架上下文机制的原理,增加代码with app.app_context():

参考链接:关于flask中 RuntimeError: Working outside of application context 引发的问题(flask中的上下文机制)

module修改1.py

from main import db,app # 直接引用main模块中的全局变量
# 创建上下文
with app.app_context():
    class Users(db.Model):
    __table__ = Table('users', db.metadata, autoload_with=db.engine, mysql_bind=db.engine)
    def find_user_by_id(self, userid):
        row = db.session.query(Users).filter(Users.userid == userid).first()
        return row
    def find_user_by_id2(self, userid):
        row = Users.query.filter(Users.userid == userid).first()
        return row

这样修改完,仍然在页面报错RuntimeError: The current Flask app is not registered with this 'SQLAlchemy' instance. Did you forget to call 'init_app', or did you create multiple 'SQLAlchemy' instances?

三、解决方案

我意识到是两个文件中应用的SQLAlchemy对象可能并非同一个(现在仍然不知道为啥,如有人知道求告知!)最终在chatgpt的帮助下得出一个比较笨,但很简单的解决方案:

解决方案如下:

具体来说,SQLAlchemy 对象需要知道它将要与哪个 Flask 应用程序实例绑定。如果在不同的 Python 文件中创建了不同的 Flask 实例,并且在每个文件中都创建了一个 SQLAlchemy 实例,则会导致这个问题。为了解决这个问题,你可以考虑将 SQLAlchemy 实例单独放在一个模块中,然后在需要使用它的地方导入它。同时,在 main.py 中导入其他模块时,也要确保它们使用的是相同的 Flask 实例。

以下是一个可能的解决方案:

  1. 在一个单独的文件(例如 database.py)中创建一个 SQLAlchemy 实例,代码如下:
    from flask_sqlalchemy import SQLAlchemy
    db = SQLAlchemy()
    
  2. 在主程序 main.py 中导入 db 对象并绑定到 Flask 应用程序实例:
    from flask import Flask
    from database import db
    app = Flask(__name__)
    app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://root:password@localhost:3306/ayangnote?charset=utf8'
    app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
    db.init_app(app)
    
  3. 在其他模块中导入 db 对象,并确保它们使用的是相同的 Flask 应用程序实例。例如,在 module.py 中:
    from database import db
    with app.app_context():
        class Users(db.Model):
            ...
    

    这样,所有模块都将使用相同的 Flask 应用程序实例和 SQLAlchemy 实例,从而避免出现不同实例之间的冲突。

最后鸣谢chatgpt,呜呜