You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flask-SQLAlchemy事件监听器无法获取更新前的旧数据库数据

解决Flask-SQLAlchemy审计日志中获取更新前旧数据的问题

你遇到的问题根源在于:before_update事件触发时,目标对象已经被修改,且SQLAlchemy会话会缓存当前对象的最新状态,直接通过User.query.get(target.id)查询会返回会话中已修改的对象,而非数据库里的原始数据。

正确的做法是使用SQLAlchemy的inspect工具获取对象的提交前原始状态,无需额外查询数据库。修改后的代码如下:

from flask_sqlalchemy import SQLAlchemy
from sqlalchemy import event, inspect
from flask import Flask

app = Flask(__name__)
app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///db"

db = SQLAlchemy(app)


class User(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(100))
    email = db.Column(db.String(100))


with app.app_context():
    db.drop_all()
    db.create_all()


@event.listens_for(User, 'before_update')
def receive_before_update(mapper, connection, target):
    # 获取对象的提交前原始状态
    state = inspect(target)
    committed_state = state.committed_state
    
    # 提取原始值,若字段未修改则使用当前值作为 fallback
    original_name = committed_state.get('name', target.name)
    original_email = committed_state.get('email', target.email)

    # 记录变更
    print(f"Updating user: {original_name} ({original_email}) to {target.name} ({target.email})")


# 添加新用户
new_user = User(name="First_User", email="s@s.com")

with app.app_context():
    db.session.add(new_user)
    db.session.commit()

# 更新用户名称
with app.app_context():
    update_record = User.query.filter_by(name="First_User").first()
    update_record.name = "new_name"
    db.session.commit()

关键说明:

  • inspect(target)获取对象的状态实例,committed_state属性存储了对象在数据库中的原始值(未被本次修改覆盖的状态)。
  • 调用committed_state.get()时,若字段未被修改,会返回None,因此用target.name作为 fallback 保证逻辑完整。

运行修改后的代码,输出会符合预期:

Updating user: First_User (s@s.com) to new_name (s@s.com)

内容的提问来源于stack exchange,提问作者ZDRuX

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 16:20:38