在 SQLModel 里用 foreign_key 主要是两步:在"多方"的模型字段上通过 Field(foreign_key="表名.列名") 建立外键,再用 Relationship() 定义模型间的关系属性,方便 Python 层面直接访问关联数据。
🧱 基础用法:定义一对多关系
以一个团队(Team)拥有多个英雄(Hero)为例:
- 定义 Team 模型("一方") :和普通模型一样,主键用 primary_key=True。
- 定义 Hero 模型("多方") :在
team_id字段上用 foreign_key="team.id"指定外键,team 是数据库中的表名(小写),不是模型类名 Team。 - 添加 Relationship 属性 :在两边分别用 Relationship(back_populates="...") 建立双向关系,这样就能通过 hero.team 或 team.heroes 直接访问关联数据。
python
from typing import Optional, List
from sqlmodel import Field, SQLModel, Relationship
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="team")
class Hero(SQLModel, table=True):
id: Optional[int] = Field(default=None, primary_key=True)
name: str
secret_name: str
age: Optional[int] = None
team_id: Optional[int] = Field(default=None, foreign_key="team.id")
team: Optional[Team] = Relationship(back_populates="heroes")
🔑 关键点说明
- 外键字符串格式 :必须是 "表名.列名",比如 "team.id",这里用的是数据库表名(小写),不是 Python 类名。
- 可空性自动推断 :如果字段类型是 Optional[int],SQLModel 会自动把该列设为可空(无 NOT NULL 约束),表示"英雄可以不属于任何战队"。
- 底层机制 :foreign_key 最终会被包装成 SQLAlchemy 的 ForeignKey 对象,在数据库中生成 FOREIGN KEY... REFERENCES... 约束。
🔗 关联查询
建立关系后,查询就很方便了:
python
from sqlmodel import Session, select
# 查询英雄,直接访问关联的团队
with Session(engine) as session:
statement = select(Hero).where(Hero.name == "Rusty-Man")
hero = session.exec(statement).first()
if hero and hero.team:
print(f"Team: {hero.team.name}")
# 反向查询:从团队找所有英雄
with Session(engine) as session:
statement = select(Team).where(Team.name == "Preventers")
team = session.exec(statement).first()
if team:
for hero in team.heroes:
print(f" - {hero.name}")
⚠️ 注意
- 如果不需要在 Python 层面通过 .team 或 .heroes 访问关联数据,只用 foreign_key 建立数据库外键约束也是可以的,但要用 JOIN 来查询关联数据。
- 删除关联数据时,可以通过 ondelete="CASCADE" 或 ondelete="RESTRICT" 控制数据库层面的行为;ondelete="SET NULL" 要求该字段必须可空(Optional[int])。