FastAPI中Pydantic序列化时过滤关联is_delete=False子数据方案
解决方案
你可以根据业务需求选择以下任意一种实现方式:
方案1:ORM关系层全局过滤(最常用)
直接在Parent模型的relationship定义中增加关联过滤条件,之后所有场景下访问parent.children都会自动排除已标记删除的子数据,不需要额外修改查询和序列化逻辑,适合全局默认不返回软删除数据的场景。
首先修正原代码中Child模型的外键定义错误(原写法parent.id = Column(...)是非法语法,模型字段不能带点号),再修改relationship配置:
from sqlalchemy import Column, Integer, Boolean, ForeignKey from sqlalchemy.orm import relationship, declarative_base Base = declarative_base() class Parent(Base): __tablename__ = "parent" id = Column(Integer, primary_key=True, nullable=False) children = relationship( "Child", backref="parent", uselist=True, # 新增关联过滤条件,自动排除已删除子项 primaryjoin="and_(Parent.id == Child.parent_id, Child.is_detele == False)" ) class Child(Base): __tablename__ = 'children' id = Column(Integer, primary_key=True, nullable=False) # 修正外键字段定义 parent_id = Column(Integer, ForeignKey(Parent.id)) is_detele = Column(Boolean, default=False)
修改完成后原有ParentBase序列化逻辑不需要做任何改动,返回结果会自动过滤掉is_detele=True的子数据。
方案2:查询时手动过滤(灵活度最高)
如果不需要全局过滤,仅在部分接口需要返回未删除的子数据,可以在查询数据库时手动过滤关联的children,通过contains_eager预加载过滤后的结果,不会影响其他场景下获取全量子数据。
代码示例:
from sqlalchemy.orm import contains_eager # 构建查询语句,join关联子表并过滤软删除数据,预加载过滤后的children parents = db.query(Parent)\ .join(Parent.children)\ .filter(Child.is_detele == False)\ .options(contains_eager(Parent.children))\ .all() # 直接用原有ParentBase序列化即可 result = [ParentBase.from_orm(p).dict() for p in parents]
方案3:序列化层过滤(无侵入性)
如果不想修改ORM定义和查询逻辑,可以直接在Pydantic序列化模型中增加校验过滤逻辑,不管ORM加载的children是否包含已删除数据,最终序列化输出时都会自动过滤。
注意原来的children = list定义过于宽泛,建议先定义对应的子模型保证类型正确:
from pydantic import BaseModel, validator class ChildBase(BaseModel): id: int parent_id: int is_detele: bool class Config: orm_mode = True class ParentBase(BaseModel): id: int children: list[ChildBase] # 新增序列化校验器,过滤已删除子项 @validator("children", pre=True) def filter_deleted_child(cls, children): return [child for child in children if not child.is_detele] class Config: orm_mode = True
注意事项
- 原代码中
is_detele疑似is_delete的拼写笔误,如果是笔误请统一修正所有引用位置的字段名,避免逻辑错误。 - 方案1的全局过滤如果在某些场景需要获取包含已删除的全量子数据,可以在查询时使用
noload或者自定义join条件绕过默认过滤。
内容的提问来源于stack exchange,提问作者rikuto
相关产品推荐
相关产品推荐

