SQLAlchemy多对多关系删除关联成员报UNIQUE约束错误如何解决
问题原因
你报错的核心原因是:步骤1中重新构造了RightSide实例,哪怕这些实例携带了已存在的主键,只要它们不是当前数据库会话(db_session)中查询出来的托管对象,SQLAlchemy就会将其识别为需要新增的临时实例,执行INSERT操作,自然会触发rightside_table.id的唯一约束冲突。
你的需求只是删除多对多的关联关系,完全不需要修改RightSide表的记录,仅需要操作关联表即可,无需新构造RightSide实例。
正确操作方法
方法1:直接操作关联属性列表(最简单)
不需要重新生成列表,直接从查询到的old_ls的rightside_members中删除你要移除的对象即可,SQLAlchemy会自动管理关联表的记录:
old_ls = db_session.query(LeftSide).filter(LeftSide.id == ls.id).one() # 移除最后一个关联的RightSide对象,如果你明确要删的是rs2也可以直接调用remove(rs2) old_ls.rightside_members.pop() db_session.commit()
方法2:基于外部属性列表更新关联
如果你的业务场景确实需要先拿到过滤后的关联对象属性列表,再更新关联,应该先基于主键从当前会话查询出对应的托管RightSide实例,再赋值:
# 先拿到要保留的RightSide的主键列表 keep_rs_ids = [rs_attrs['id'] for rs_attrs in ls.rightside_members] keep_rs_ids.pop() # 去掉要删除的rs2的id old_ls = db_session.query(LeftSide).filter(LeftSide.id == ls.id).one() # 从当前会话查询要保留的托管实例 updated_rightside_members = db_session.query(RightSide).filter(RightSide.id.in_(keep_rs_ids)).all() # 赋值后SQLAlchemy会自动删除不在列表中的关联记录 old_ls.rightside_members = updated_rightside_members db_session.commit()
方法3:直接操作关联表删除(适合批量场景)
如果关联的数据量很大,不想加载全部关联对象,可以直接操作中间关联表删除对应记录:
# 先找到要删除的rs2的id delete_rs_id = ls.rightside_members[-1]['id'] old_ls = db_session.query(LeftSide).filter(LeftSide.id == ls.id).one() # 直接删除关联表中对应的关联记录 db_session.execute( left_right_association_table.delete() .where(left_right_association_table.c.leftside_id == old_ls.id) .where(left_right_association_table.c.rightside_id == delete_rs_id) ) db_session.commit()
内容的提问来源于stack exchange,提问作者Jinghui Niu
相关产品推荐
相关产品推荐

