如何在SQLModel中通过两层外键建立A与C的直接关联?
问题分析
你遇到的错误核心原因是:A.c 这个 Relationship 没有对应的直接外键字段,SQLModel 无法自动推断 A 和 C 的关联逻辑——当前 A 与 C 仅通过 B 表间接关联,没有直接的外键约束。
解决方案
方案一:混合属性快速访问(只读场景)
无需修改数据库结构,给 A 类添加一个混合属性,通过已有的 B 关联间接获取 C 对象:
from sqlalchemy.ext.hybrid import hybrid_property class A(SQLModel, table=True): id: int | None = Field(default=None, primary_key=True) b_id: int | None = Field(default=None, foreign_key="b.id") b: 'B' = Relationship(back_populates='as') @hybrid_property def c(self) -> 'C': return self.b.c if self.b else None class B(SQLModel, table=True): id: int | None = Field(default=None, primary_key=True) c_id: int | None = Field(default=None, foreign_key='c.id') as: list[A] = Relationship(back_populates='b') c: 'C' = Relationship(back_populates='bs') class C(SQLModel, table=True): id: int | None = Field(default=None, primary_key=True) bs: list[B] = Relationship(back_populates='c')
使用时直接通过 a.c 即可获取对应的 C 对象,此方式仅适用于读取操作,无法通过 A 直接修改 C 的关联。
方案二:带手动关联条件的只读 Relationship(支持查询过滤)
如果需要通过 A 直接查询 C(例如 select(A).join(A.c)),可以用 viewonly=True 结合 primaryjoin 手动指定关联逻辑:
class A(SQLModel, table=True): id: int | None = Field(default=None, primary_key=True) b_id: int | None = Field(default=None, foreign_key="b.id") b: 'B' = Relationship(back_populates='as') c: 'C' = Relationship( viewonly=True, primaryjoin="A.b_id == B.id and B.c_id == C.id", uselist=False # 匹配当前结构:1个A对应1个B,1个B对应1个C ) class B(SQLModel, table=True): id: int | None = Field(default=None, primary_key=True) c_id: int | None = Field(default=None, foreign_key='c.id') as: list[A] = Relationship(back_populates='b') c: 'C' = Relationship(back_populates='bs') class C(SQLModel, table=True): id: int | None = Field(default=None, primary_key=True) bs: list[B] = Relationship(back_populates='c')
primaryjoin 明确告知 ORM 关联路径,viewonly=True 表示该关系仅用于查询读取,不支持写入操作。若你的业务中存在一个 A 对应多个 C 的场景,需将 uselist 改为 True,并将 c 的类型改为 list[C]。
内容的提问来源于stack exchange,提问作者Michael Piccirillo
相关产品推荐
相关产品推荐

