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,但出现了其他错误。
原因分析
- SQLAlchemy会话关闭时机冲突:你在
crud_update_by_id的finally块里直接关闭了数据库会话db.close()。FastAPI序列化ORM对象的动作发生在接口函数返回之后,此时会话已经关闭,而SQLAlchemy ORM对象默认是懒加载属性,无法再从数据库读取数据,最终序列化出空对象。 - 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
相关产品推荐
相关产品推荐

