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

FastAPI返回空SQLAlchemy对象:print语句影响返回结果求解

问题描述

我有如下更新数据的异步函数(其他同类函数也存在相同问题):

async def update_row_by_id(db: Session, tableOrm, tableModel, object_id:int):
    obj_update = fetch_object_by_id(db, tableOrm, object_id)
    for field in tableModel.model_dump(exclude_unset=True):
        setattr(obj_update, field, getattr(tableModel, field))

    try:
        if(obj_update.updated_by is None):
            obj_update.updated_by = db.query(literal_column("current_user"))
        obj_update.updated_at = datetime.now()
    except AttributeError:
        pass
    try:
        db.commit()
    except (ProgrammingError,IntegrityError, PendingRollbackError) as e:
        db.rollback()
        print(e._message())
        raise HTTPException(status_code = status.HTTP_406_NOT_ACCEPTABLE, detail = e._message())
    return obj_update

接口调用代码:

@router.put(urlIdRoute, status_code=200)
async def crud_update_by_id(obj_id:int, obj_model:modelBase):
    db = SessionLocal()
    try:
        res = await update_row_by_id(db, orm, obj_model, obj_id)
        return res
    finally:
        db.close()

查询数据的函数:

def fetch_object_by_id(db: Session, tableOrm, object_id:int):
    obj = db.scalar(select(tableOrm).filter_by(id = object_id))
    if obj is None:
        raise common_404_exception(tableOrm.__tablename__, object_id)
    return obj

遇到的问题:在FastAPI的/docs页面测试接口时,返回空对象{},但数据库里的数据已经成功更新;如果在return语句前加print(obj_update),接口就能正常返回数据。请问为什么print语句会影响返回结果?怎么不用print解决这个问题?我试过给查询函数加async/await,但出现了其他错误。

原因分析
  1. SQLAlchemy会话关闭时机冲突:你在crud_update_by_id的finally块里直接关闭了数据库会话db.close()。FastAPI序列化ORM对象的动作发生在接口函数返回之后,此时会话已经关闭,而SQLAlchemy ORM对象默认是懒加载属性,无法再从数据库读取数据,最终序列化出空对象。
  2. print语句的触发作用:print(obj_update)会强制读取ORM对象的所有属性,此时会话还未关闭,SQLAlchemy会即时从数据库加载属性数据到对象中,后续序列化时自然能拿到完整数据。
解决方案

以下几种方法都能解决问题,可根据你的场景选择:

方法1:会话关闭前转成Pydantic模型

在关闭数据库会话之前,把ORM对象转换成对应的Pydantic模型,这样序列化时无需依赖数据库会话:

@router.put(urlIdRoute, status_code=200)
async def crud_update_by_id(obj_id:int, obj_model:modelBase):
    db = SessionLocal()
    try:
        res = await update_row_by_id(db, orm, obj_model, obj_id)
        # 将ORM对象转换为Pydantic模型后返回
        return modelBase.from_orm(res)
    finally:
        db.close()

方法2:提交后刷新ORM对象

在update_row_by_id的db.commit()之后,调用db.refresh(obj_update)强制从数据库加载最新数据到ORM对象,确保对象属性已被填充:

async def update_row_by_id(db: Session, tableOrm, tableModel, object_id:int):
    obj_update = fetch_object_by_id(db, tableOrm, object_id)
    for field in tableModel.model_dump(exclude_unset=True):
        setattr(obj_update, field, getattr(tableModel, field))

    try:
        if(obj_update.updated_by is None):
            obj_update.updated_by = db.query(literal_column("current_user"))
        obj_update.updated_at = datetime.now()
    except AttributeError:
        pass
    try:
        db.commit()
        # 刷新对象,加载最新数据到内存
        db.refresh(obj_update)
    except (ProgrammingError,IntegrityError, PendingRollbackError) as e:
        db.rollback()
        print(e._message())
        raise HTTPException(status_code = status.HTTP_406_NOT_ACCEPTABLE, detail = e._message())
    return obj_update

方法3:用依赖管理控制会话生命周期

使用FastAPI的依赖注入来管理数据库会话,这样会话会在响应完全返回后才关闭,避免序列化时会话已关闭的问题:

# 定义数据库会话依赖
def get_db():
    db = SessionLocal()
    try:
        yield db
    finally:
        db.close()

# 修改接口,通过依赖注入获取会话
@router.put(urlIdRoute, status_code=200)
async def crud_update_by_id(obj_id:int, obj_model:modelBase, db: Session = Depends(get_db)):
    res = await update_row_by_id(db, orm, obj_model, obj_id)
    return res

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 12:15:17