如何避免在交换唯一值时在唯一性约束上出现SQLAlchemy IntegrityError



我有如下SQLAlchemy模型(从实际实现中抽象出来(

class Parent():
id = Column(postgresql.UUID, primary_key=True)
class Child():
id = Column(postgresql.UUID, primary_key=True)
parent_id = (postgresql.UUID,sqlalchemy.ForeignKey(Parent.id), nullable=False, index=True)
order = sa_schema.Column(postgresql.SMALLINT)

我对parent_id和order有一个唯一性约束,所以父对象上的子对象的排序是唯一的。我想写代码来允许对这些子级进行重新排序,例如,如果我有按该顺序排列的子级A B C D E,并想将子级B的顺序从2更改为4,我将C从3更改为2,D从4更改为3。所有这些都在起作用,但当我提交事务时,我会得到一个IntegrityError,声明其中一个order/pparent_id对已经存在(每次都是随机的(。我已经关闭了自动冲洗,有人知道我该怎么做吗?示例代码(显然这只处理订单增加的情况(:

children_to_update = session.query(models.Child).filter(
models.Child.parent_id == parent_id,
models.Child.order <= new_order,
models.Child.order > original_order,
).with_for_update(nowait=True).all()
for child_to_update in children_to_update:
child_to_update.order = child_to_update.order - 1
session.add(child_to_update)
original_child.order = new_order
session.add(original_child)
session.commit()

要实现这一点,首先需要使(parent_id, order)上的唯一约束可延迟。

然后,您需要在查询之前通过发送set constraints <constraint name|all> deferred;来推迟约束

延迟约束将在commit上自动检查。

最新更新