Python 学习笔记:SQLModel 使用外键关联查询数据

在 SQLModel 里用 foreign_key 主要是两步:在"多方"的模型字段上通过 Field(foreign_key="表名.列名") 建立外键,再用 Relationship() 定义模型间的关系属性,方便 Python 层面直接访问关联数据。‌‌

🧱 基础用法:定义一对多关系

以一个团队(Team)拥有多个英雄(Hero)为例:

  1. ‌定义 Team 模型("一方") ‌:和普通模型一样,主键用 primary_key=True。
  2. ‌定义 Hero 模型("多方") ‌:在 team_id 字段上用 foreign_key="team.id"指定外键,team 是数据库中的表名(小写),不是模型类名 Team。
  3. ‌添加 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])。‌‌
相关推荐
王中阳Go14 分钟前
两个入口答案不一致先别调模型:6 行入口口径对账表(附脚本)
人工智能·后端·python·大语言模型·1024程序员节
BK贝壳25 分钟前
bool-hybrid-array 落盘我只认 .bha:用 Create_BHA / Ask_BHA 做布尔数组序列化
数据结构·python·numpy·1024程序员节
Sakura_j_h_1 小时前
Python 在定时任务里输出 emoji,UnicodeEncodeError 从哪来
开发语言·字符编码·windows·python·定时任务
supabc1232 小时前
欧盟电子发票(XRechnung/Peppol/ZUGFeRD)踩坑记:用 Python 不装 Java 跑官方校验规则
xml·python·开源·电子发票·1024程序员节
ZhengEnCi3 小时前
AI Agent工具调用防护层怎么写-一份能直接跑的Python四层拦截实现
python·llm·agent
ZhengEnCi3 小时前
AI Agent工具误调用怎么解决-从参数校验到高危二次确认的四层工程防线
python·llm·agent
镜子AI4 小时前
镜子AI工程教程:用Python实现关键词布局检查器与语义改写查重(附完整代码)
人工智能·python·microsoft
小oo呆5 小时前
【学习心得】Python协程
python
信誓旦旦的程序猿5 小时前
【Python量化实战宝典 #22】涨跌停、连板情绪手册:情绪指标构建(Python 可跑)
python·1024程序员节·股票数据api·股票数据api接口·股票api数据接口·股票量化数据api·股票量化数据接口
gCode Teacher 格码致知5 小时前
Pandas教学-21:subplots的使用
python·pandas·1024程序员节