Fast API嵌套Schema处理及数据存储报错问题排查
问题分析与解决方案
错误原因
你的Book SQLAlchemy模型仅定义了publisher_id外键字段和publishers关系属性,没有名为publisher的字段,但你将包含嵌套publisher对象的请求数据直接解构传入Book构造函数,导致触发TypeError: 'publisher' is an invalid keyword argument for Book错误。
另外注意你的CRUD代码里有笔误:obj_in_data = jsonable_encoder(obj_in_data)应该改为obj_in_data = jsonable_encoder(obj_in),否则会引用未定义的变量。
解决方案
方案1:手动移除无效字段
在构造Book对象前,从序列化后的字典中删除publisher键:
class CRUDBook(CRUDBase[Book, BookCreate, BookUpdate]): def create_with_owner( self, db: Session, *, obj_in: BookCreate, owner_id: int ) -> Book: # 检查并创建publisher(原代码逻辑保留) publisher = crud.publisher.show(db=db, name=obj_in.publisher.name) if not publisher: publisher = crud.publisher.create( db=db, obj_in=PublisherCreate(name=obj_in.publisher.name) ) # 修正笔误,序列化请求数据 obj_in_data = jsonable_encoder(obj_in) # 移除Book模型不接受的publisher字段 del obj_in_data["publisher"] db_obj = self.model( **obj_in_data, owner_id=owner_id, publisher_id=publisher.id, ) db.add(db_obj) db.commit() db.refresh(db_obj) return db_obj
方案2:利用Pydantic的字段排除功能
直接通过Pydantic的dict()方法或jsonable_encoder的exclude参数过滤掉publisher字段,更简洁:
class CRUDBook(CRUDBase[Book, BookCreate, BookUpdate]): def create_with_owner( self, db: Session, *, obj_in: BookCreate, owner_id: int ) -> Book: publisher = crud.publisher.show(db=db, name=obj_in.publisher.name) if not publisher: publisher = crud.publisher.create( db=db, obj_in=PublisherCreate(name=obj_in.publisher.name) ) # 方式1:用dict方法排除publisher obj_in_data = obj_in.dict(exclude={"publisher"}) # 方式2:或用jsonable_encoder带exclude参数 # obj_in_data = jsonable_encoder(obj_in, exclude={"publisher"}) db_obj = self.model( **obj_in_data, owner_id=owner_id, publisher_id=publisher.id, ) db.add(db_obj) db.commit() db.refresh(db_obj) return db_obj
优化建议:统一关系字段命名
你的Book模型中关系字段命名为publishers(复数),但业务逻辑里一个书籍对应一个出版商,建议改为单数publisher,避免语义混淆:
# 修改Book模型的关系定义 class Book(Base): # ... 其他字段保持不变 publisher_id = Column(Integer, ForeignKey("publisher.id")) publisher = relationship("Publisher", back_populates="books") # 改为单数 # 对应修改Publisher模型的back_populates class Publisher(Base): # ... 其他字段保持不变 books = relationship("Book", back_populates="publisher")
内容的提问来源于stack exchange,提问作者Olaw2jr
相关产品推荐
相关产品推荐

