SQLAlchemy编辑一对多关联数据时如何自动处理子项的增删操作
正确实现方案
第一步:配置一对多关联的级联规则
你只需要在定义Parent和Child的ORM模型时,给父表的关联属性配置正确的级联参数即可,不需要自己维护新旧子项对比逻辑:
from sqlalchemy import Column, Integer, ForeignKey from sqlalchemy.orm import relationship from sqlalchemy.ext.declarative import declarative_base Base = declarative_base() class Parent(Base): __tablename__ = 'parent' id = Column(Integer, primary_key=True) # 核心配置:cascade参数加入delete-orphan children = relationship( "Child", back_populates="parent", cascade="all, delete-orphan", single_parent=True ) class Child(Base): __tablename__ = 'child' id = Column(Integer, primary_key=True) parent_id = Column(Integer, ForeignKey('parent.id')) parent = relationship("Parent", back_populates="children")
参数说明:
cascade="all":将父对象的新增、修改、删除操作级联到关联的子对象,你之前新增父记录时子对象自动插入就是这个配置的作用delete-orphan:核心配置,只要子对象被移出parent.children集合,SQLAlchemy就会将其标记为待删除,commit时自动执行DELETE操作single_parent=True:配合delete-orphan使用,约束一个子对象只能属于一个父对象,避免误删数据
第二步:更新场景的操作流程
完全不需要深拷贝存储初始子项列表,直接操作parent.children关联集合即可:
- 加载待编辑的父记录时,直接将关联子项绑定到GUI表格:
# 加载id为目标值的父记录 self.parent = db.session.query(Parent).get(target_parent_id) # 直接将self.parent.children绑定为GUI表格的数据源即可
- 用户新增子项时,和新建场景操作完全一致:
self.parent.children.append(new_child)
- 用户删除子项时,和新建场景操作完全一致:
self.parent.children.remove(target_child)
- 保存时不需要额外的删除、新增旧子项逻辑,直接提交即可:
def save(self): # 不需要主动调用add,会话加载的对象变更会被自动跟踪 db.session.commit() self.closeGUI()
原理说明
SQLAlchemy的会话会自动跟踪所有加载到会话中的ORM对象的状态,包括关联集合的增减变更。配置级联规则后,commit时会自动完成三类操作:
- 给新增到
children集合中的新子对象执行INSERT - 给仍在
children集合中、字段有修改的子对象执行UPDATE - 给原本在
children集合中、已被移出的子对象执行DELETE
注意事项
- 不要将子项单独查询后存储到脱离父对象的独立变量中,必须直接操作
parent.children集合,SQLAlchemy才能跟踪到变更 - 如果加载数据和保存操作不在同一个数据库会话中,保存前需要先将父对象合并到当前会话:
self.parent = db.session.merge(self.parent) - 不要对ORM对象执行深拷贝操作,深拷贝出来的对象会脱离会话的状态跟踪,导致变更无法被识别
内容的提问来源于stack exchange,提问作者user12181582
相关产品推荐
相关产品推荐

