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

SQLAlchemy中如何通过主表属性获取其主键作为外键关联的子表

从父表ORM对象反向获取关联子表及批量插入实现方案

反向获取关联子表的通用方法

根据你的使用场景,有两种实现方案:

方案1:基于已配置的relationship属性获取(性能更高,推荐)

只要你定义ORM映射时配置了relationship属性,不管单向还是双向关联,都可以直接通过属性拿到关联子表信息,通用实现如下:

from sqlalchemy.orm import RelationshipProperty

# 遍历获取User类所有关联的子表
for attr_name, attr in User.__mapper__.attrs.items():
    if isinstance(attr, RelationshipProperty):
        # 关联的子映射类
        child_cls = attr.entity.class_
        # 子表的Table对象
        child_table = child_cls.__table__
        # 子表名
        child_table_name = child_cls.__tablename__
        print(f"关联属性{attr_name}对应的子表:{child_table_name}")

# 已知关联属性名为address时可直接获取
address_table = User.address.property.entity.class_.__table__

该方法适配所有带relationship配置的关联关系,无需遍历全库元数据

方案2:基于外键约束遍历获取(无relationship配置时使用)

如果没有配置ORM的relationship,可直接遍历元数据中所有表的外键约束,找到所有引用了父表的子表:

parent_table = User.__table__
child_tables = []
# 遍历所有已注册的表
for table in Base.metadata.tables.values():
    for fk_constraint in table.foreign_key_constraints:
        if fk_constraint.referred_table == parent_table:
            child_tables.append(table)
print(child_tables) # 输出包含address表

批量插入关联子表的完整实现

你现在只执行了User表的插入语句,SQLAlchemy Core层面不会自动处理ORM级联逻辑,所以需要手动处理关联子表的插入,完整流程如下:

import pandas as pd
from sqlalchemy.dialects.sqlite import insert

# 1. 处理User表的批量插入更新,返回生成的主键ID
user_table = User.__table__
# 提取User对应的字段数据
user_df = df[["name"]].copy()
user_records = user_df.to_dict(orient="records")

user_insert_stmt = insert(user_table).values(user_records).returning(user_table.c.id)
user_pks = [pk.name for pk in user_table.primary_key]
user_update_cols = {col.name: col for col in user_insert_stmt.excluded if col.name not in user_pks}
user_upsert_stmt = user_insert_stmt.on_conflict_do_update(
    index_elements=user_pks,
    set_=user_update_cols
)

with engine.connect() as conn:
    result = conn.execute(user_upsert_stmt)
    # 按插入顺序拿到所有用户主键ID
    user_ids = [row[0] for row in result]
    conn.commit()

# 2. 处理Address表的批量插入更新
address_table = User.address.property.entity.class_.__table__
# 组装Address数据,关联对应用户的主键
address_records = []
for idx, company_name in enumerate(df["company_name"]):
    address_records.append({
        "user_id": user_ids[idx],
        "company_name": company_name
    })

address_insert_stmt = insert(address_table).values(address_records)
address_pks = [pk.name for pk in address_table.primary_key]
address_update_cols = {col.name: col for col in address_insert_stmt.excluded if col.name not in address_pks}
address_upsert_stmt = address_insert_stmt.on_conflict_do_update(
    index_elements=address_pks,
    set_=address_update_cols
)

with engine.connect() as conn:
    conn.execute(address_upsert_stmt)
    conn.commit()

如果是一个User对应多个Address的场景,只需提前整理好同一个用户对应的多条Address数据,再关联user_id即可


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.02 11:30:06