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

SQLModel继承问题:BaseUser中Role字段无法在AppUser中填充

解决SQLModel继承基类中Relationship不生效的问题

问题原因

SQLModel 0.0.12中,标记为table=False的基类里定义的Relationship不会自动被继承到子类的表模型中。这是因为ORM映射构建逻辑仅处理当前表类直接定义的关系配置,非表基类中的关系不会被纳入子类的映射元数据。

解决方案

方案一:使用declared_attr动态定义关系

通过SQLAlchemy的declared_attr装饰器,让基类中的关系在子类继承时被正确生成并注册到ORM映射中:

from sqlmodel import Field, SQLModel, Column
from sqlalchemy import create_engine
from sqlalchemy.orm import relationship, declared_attr
from sqlalchemy.pool import StaticPool
from typing import Optional
from sqlalchemy import BigInteger
from sqlmodel import Relationship, Session, select


class Base(SQLModel, table=False):
    id: Optional[int] = Field(sa_column=Column(BigInteger(), default=None, primary_key=True))

class UserRole(Base, table=True):
    name: str

class BaseUser(Base, table=False):
    username: str
    role_id: int = Field(default=None, foreign_key="userrole.id")
    
    @declared_attr
    def role(cls):
        return Relationship(sa_relationship=relationship("UserRole", lazy="joined"))

class AppUser(BaseUser, table=True):
    email: str


engine = create_engine(
        'sqlite:///demo2.db',
        connect_args={"check_same_thread": False},
        poolclass=StaticPool,
        echo=True
)
SQLModel.metadata.create_all(engine)

with Session(engine) as session:
        statement = select(AppUser)
        results = session.exec(statement)
        items = results.all()

方案二:子类显式复用基类关系定义

如果不想使用declared_attr,可以在子类中直接引用基类的role属性,避免重复编写关系配置:

class AppUser(BaseUser, table=True):
    email: str
    role: UserRole = BaseUser.role

原理说明

  • declared_attr会在子类创建时动态生成关系属性,确保SQLModel的ORM映射系统能识别并处理这个关联。
  • 直接引用基类的role属性,相当于将基类的关系配置复制到子类中,让SQLModel在处理子类表模型时,将该关系纳入映射元数据。

内容的提问来源于stack exchange,提问作者Gabriel Macus

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.05 17:33:20