SQLAlchemy多对多关系删除操作



我有一个由关联表链接的多对多关系,如下所示:

left_right_association_table = Table("left_right_association_table", Base.metadata,
Column('leftside_id', Integer, ForeignKey('leftside_table.id')),
Column('rightside_id', Integer, ForeignKey('rightside_table.id'))
)
class LeftSide(Base):
...
rightside_members = relationship("RightSide", secondary=left_right_association_table, backref="leftside", lazy="joined")
...

class RightSide(Base):
...

现在我有一个LeftSide实例,RightSide实例的list作为其rightside_members属性:

ls = LeftSide(**kw)
rs1 = RightSide(**kw)
rs2 = RightSide(**kw)
ls.rightside_members.append(rs1)
ls.rightside_members.append(rs2)

然后,我想删除一个列表成员:rs2.

步骤1:我复制rightside_members列表:

updated_rightside_members = [RightSide(**rs_attrs) for rs_attrs in ls.rightside_members] # each `rs` object already has primary key
updated_rightside_members.pop() # remove the second item from the list

步骤2:我从数据库中检索ls:

old_ls = db_session.query(LeftSide).filter(LeftSide_id == ls.id).one()

步骤3:我将updated_rightside_members添加到old_ls:

old_ls.rightside_members = updated_rightside_members

步骤4:commit to database.

db_session.commit()

然后我得到这个错误:

sqlite3.IntegrityError: UNIQUE constraint failed: rightside_table.id

在我看来,SQLAlchemy认为我试图将复制的rs1放回数据库,而不是从数据库中删除它的兄弟rs2

我应该如何做这个删除操作?

我已经解决了这个问题。首先,我真的想指出,仔细阅读文档是有帮助的。使用映射类初始化实例并不意味着会话知道这个对象,至少在使用Session.add()方法之前是这样。

所以,正确的步骤应该是这样的:
  1. 决定传入参数是否包含代表实例主键的id。如果是,那么正确的方法不是初始化它,而是从数据库中查询它。这样,Session将确保查询的对象在其identity map中具有唯一的对象id。
  2. 如果不包含id属性,则初始化它,并将其添加到成员列表中。