You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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等字段继承时重复定义的警告)。

错误原因

  1. SQLModel的表模型(带table=True)中的Relationship字段本质是SQLAlchemy的Mapped类型,Pydantic 2.x默认无法为该类型生成校验schema;
  2. 直接继承SQLModel表模型时,Pydantic会尝试处理所有继承字段,包括ORM专用的关系字段,从而触发报错;
  3. 字段阴影警告是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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.04 22:50:57