SQLAlchemy自关联查询后JSON序列化遇递归错误的解决方法
解决自关联模型序列化递归错误的方案
原因分析
自关联的created_by字段会让每个User对象包含另一个User实例,而这个实例又有自己的created_by属性,序列化时会无限递归遍历这种关联关系,最终触发递归深度超限错误。
具体解决方法
方法1:序列化时直接排除关联字段
在jsonable_encoder中通过exclude参数指定排除created_by字段,避免递归遍历:
jd = jsonable_encoder(list(results), exclude_none=True, exclude={"created_by"})
如果需要保留创建者ID而非整个对象,只需保留created_by_id字段、排除created_by即可。
方法2:使用Pydantic模型控制序列化结构
定义Pydantic模型时明确指定要序列化的字段,避免包含循环引用的关联对象:
from pydantic import BaseModel class UserResponse(BaseModel): id: int created_by_id: int | None # 添加其他需要返回的字段,不要包含created_by # 序列化时转换为Pydantic模型列表 user_list = list(results) jd = UserResponse.model_validate(user_list, many=True).model_dump(exclude_none=True)
如果需要展示创建者的基础信息,可以定义递归模型并自动处理循环:
class UserResponse(BaseModel): id: int created_by_id: int | None created_by: "UserResponse" | None = None UserResponse.model_rebuild() # 解决自引用模型的前置声明问题 jd = UserResponse.model_validate(user_list, many=True).model_dump(exclude_none=True)
Pydantic会自动处理自引用的递归序列化,不会触发深度超限。
方法3:修改SQLAlchemy查询,不加载关联对象
在查询时使用noload避免加载created_by关联,从根源上消除对象的循环引用:
query = select(User) \ .outerjoin(alias_user.created_by) \ .options(defer(User.hashed_password), noload(User.created_by))
查询返回的User对象不会包含created_by实例,序列化时自然不会触发递归。
内容的提问来源于stack exchange,提问作者Hatef Alipoor
相关产品推荐
相关产品推荐

