使用SQLModel嵌套字段时触发TypeError: cannot pickle 'module' object错误
问题分析与解决方案
问题根源
SQLModel 0.0.8作为FastAPI的response_model时,FastAPI会触发模型实例的序列化/持久化流程(涉及pickle操作),而你使用的CompressedJSONType字段对应的模型实例中,可能持有了不可被pickle序列化的模块对象引用(比如该类型内部关联的SQLAlchemy模块对象)。由于SQLModel同时集成了SQLAlchemy的ORM特性和Pydantic的序列化特性,当作为响应模型时,ORM层面的某些内部属性会被带入序列化流程,触发pickle错误。
arbitrary_types_allowed=True无效的原因是:这个配置仅解决Pydantic对自定义类型的校验问题,无法处理pickle序列化时的模块对象引用问题。
解决方案
1. 拆分数据库模型与响应模型(推荐)
将SQLModel的数据库操作模型和纯Pydantic的响应模型分开,避免ORM属性干扰序列化:
from sqlmodel import SQLModel, Field, Session, select from pydantic import BaseModel from fastapi import FastAPI, Depends import sqlalchemy as sa import sqlalchemy_schemadisplay as sam # 数据库模型(仅用于数据库操作) class ZIPCodeDB(SQLModel, table=True): id: int | None = Field(default=None, primary_key=True) data: dict = Field(sa_column=sa.Column(sam.types.CompressedJSONType)) # 响应模型(仅用于接口返回) class ZIPCodeResponse(BaseModel): id: int data: dict app = FastAPI() # 数据库会话依赖 def get_db(): with Session(engine) as session: yield session # FastAPI接口示例 @app.get("/zipcode/{zipcode_id}", response_model=ZIPCodeResponse) def get_zipcode(zipcode_id: int, db: Session = Depends(get_db)): db_zipcode = db.exec(select(ZIPCodeDB).where(ZIPCodeDB.id == zipcode_id)).first() return db_zipcode # Pydantic会自动转换SQLModel实例为响应模型
2. 自定义SQLModel的pickle序列化逻辑
在SQLModel类中添加__getstate__方法,移除不可序列化的ORM内部属性:
class ZIPCode(SQLModel, table=True): id: int | None = Field(default=None, primary_key=True) data: dict = Field(sa_column=sa.Column(sam.types.CompressedJSONType)) def __getstate__(self): # 复制实例状态,移除SQLAlchemy ORM相关的不可pickle属性 state = self.__dict__.copy() state.pop("_sa_instance_state", None) return state
3. 升级SQLModel版本
SQLModel 0.0.8属于早期版本,后续版本(如0.10.x及以上)对序列化和pickle逻辑做了优化,可能已修复该问题。执行升级命令:
pip install --upgrade sqlmodel
内容的提问来源于stack exchange,提问作者TeodorYantcheff
相关产品推荐
相关产品推荐

