我有一个sqlalchemy实体有两个外键,因为它可以有两个完全不同的父母之一。我们使用地址,客户和供应商进行说明。 地址可以属于客户或供应商(在我的情况下也可以有子女)。
我希望地址及其子项在父项为零时自动删除,即 Customer 或 Supplier 都不会引用它。
我最初将其实现为
class Address(Base):
__tablename__ = 'addresses'
id = Column(Integer, primary_key=True)
customer_id = Column(Integer, ForeignKey('customers.id')
supplier_id = Column(Integer, ForeignKey('suppliers.id')
# etc ...
根据sqlalchemy文档,实现Generic Associations的规范方法是使用 table-per-related 或 table-per-association 。这两个似乎都没有解决删除级联的问题:
delete-orphan
如何在这里工作。 在sqlalchemy中使用通用关联处理delete-orphan
级联的正确方法是什么?
答案 0 :(得分:0)
找到答案。在SO上有几个related questions,人们在多对多关系中遇到这个问题(基本上是每个关联表是什么)。还有一个SQLAlchemy Wiki条目,描述了如何解决问题。
解决方案是基本上通过实现在每次刷新后清理的事件监听器来手动执行delete-orphan
:
@event.listens_for(Session, 'after_flush')
def delete_address_orphans(session, ctx):
if any(isinstance(i, Address) for i in session.dirty):
query = session.query(Address).\
filter_by(customer=None, supplier=None)
orphans = query.all()
for orphan in orphans:
session.delete(orphan)
请注意,在我的情况下,我首先加载孤立,而不是简单地将.delete()
添加到查询语句中。这是因为后者会绕过地址实体上的级联,因此不会删除地址的子节点。