Sqlmodel 0.0.14添加字段时关联关系触发Pydantic异常如何解决?
问题修复:SQLModel + Pydantic 2.x 下 HeroOut 类报错问题
环境与问题背景
使用Python 3.12、sqlmodel0.0.14、pydantic2.5.2时,原有继承SQLModel表模型的HeroOut类出现报错,原代码在旧版SQLModel及Pydantic 1.x环境可正常运行。
原报错代码
from typing import List, Optional from sqlmodel import Field, Relationship, SQLModel class HeroTeamLink(SQLModel, table=True): team_id: Optional[int] = Field( default=None, foreign_key="team.id", primary_key=True ) hero_id: Optional[int] = Field( default=None, foreign_key="hero.id", primary_key=True ) class Team(SQLModel, table=True): id: Optional[int] = Field(default=None, primary_key=True) name: str = Field(index=True) headquarters: str heroes: List["Hero"] = Relationship(back_populates="teams", link_model=HeroTeamLink) class Hero(SQLModel, table=True): id: Optional[int] = Field(default=None, primary_key=True) name: str = Field(index=True) secret_name: str age: Optional[int] = Field(default=None, index=True) teams: List[Team] = Relationship(back_populates="heroes", link_model=HeroTeamLink) class HeroOut(Hero): is_new: bool = Field(default=False)
核心错误信息
pydantic.errors.PydanticSchemaGenerationError: Unable to generate pydantic-core schema for sqlalchemy.orm.base.Mapped[typing.List[app.main.Team]]. Set `arbitrary_types_allowed=True` in the model_config to ignore this error or implement `__get_pydantic_core_schema__` on your type to fully support it.
同时伴随字段阴影警告(如teams、id等字段继承时重复定义的警告)。
错误原因
- SQLModel的表模型(带
table=True)中的Relationship字段本质是SQLAlchemy的Mapped类型,Pydantic 2.x默认无法为该类型生成校验schema; - 直接继承SQLModel表模型时,Pydantic会尝试处理所有继承字段,包括ORM专用的关系字段,从而触发报错;
- 字段阴影警告是Pydantic 2.x对继承字段的校验逻辑更严格导致。
修复方案
方案一:分离数据模型与表模型(推荐)
创建独立的基础数据模型(不带table=True),表模型继承基础模型,输出模型也继承基础模型,避免直接继承带ORM关系的表模型。
修改后代码:
from typing import List, Optional from sqlmodel import Field, Relationship, SQLModel class HeroTeamLink(SQLModel, table=True): team_id: Optional[int] = Field( default=None, foreign_key="team.id", primary_key=True ) hero_id: Optional[int] = Field( default=None, foreign_key="hero.id", primary_key=True ) # 定义团队基础数据模型 class TeamBase(SQLModel): id: Optional[int] = Field(default=None, primary_key=True) name: str = Field(index=True) headquarters: str # 团队表模型,继承基础模型并添加ORM关系 class Team(TeamBase, table=True): heroes: List["Hero"] = Relationship(back_populates="teams", link_model=HeroTeamLink) # 定义英雄基础数据模型 class HeroBase(SQLModel): id: Optional[int] = Field(default=None, primary_key=True) name: str = Field(index=True) secret_name: str age: Optional[int] = Field(default=None, index=True) # 英雄表模型,继承基础模型并添加ORM关系 class Hero(HeroBase, table=True): teams: List[Team] = Relationship(back_populates="heroes", link_model=HeroTeamLink) # 输出模型继承基础数据模型,添加自定义字段 class HeroOut(HeroBase): is_new: bool = Field(default=False) # 若需返回团队数据,可添加对应的基础模型类型 # teams: List[TeamBase] = []
方案二:配置模型允许任意类型并排除ORM字段
通过model_config允许任意类型跳过校验,同时排除不需要的ORM关系字段,适合快速临时修复。
修改后代码:
class HeroOut(Hero): is_new: bool = Field(default=False) model_config = {"arbitrary_types_allowed": True, "exclude": {"teams"}}
或者通过字段定义直接排除:
class HeroOut(Hero): is_new: bool = Field(default=False) teams: Optional[List[Team]] = Field(exclude=True, default=None)
方案说明
- 方案一遵循SQLModel设计规范,分离数据传输模型与数据库表模型,避免ORM字段干扰Pydantic的schema生成,同时消除字段阴影警告,是长期维护的最优选择;
- 方案二通过绕过类型检查快速解决报错,但会保留字段阴影警告,且可能隐藏其他类型问题,仅适合临时场景。
内容的提问来源于stack exchange,提问作者tobias
相关产品推荐
相关产品推荐

