SQLAlchemy:在多表多态中删除
我有一个这样的模型层级:
class Foo(Base):
id = Column(
Integer,
Sequence('foo_id_seq', start=1001, increment=1),
primary_key=True
)
discriminator = Column('type', String(20), nullable=False)
__tablename__ = 'foo'
__mapper_args__ = {
'polymorphic_on': discriminator,
'polymorphic_identity': 'foo',
}
class Bar(Foo):
id = Column(Integer, ForeignKey('foo.id'), primary_key=True)
__tablename__ = 'bar'
__mapper_args__ = {
'polymorphic_identity': 'bar',
}
当我尝试用 db.query(Foo).delete()
删除所有的 Foo
实例时,我遇到了这个错误:
IntegrityError: (IntegrityError) ERROR: update or delete on table "foo" violates foreign key constraint "bar_foo_id_fkey" on table "bar"
DETAIL: Key (id)=(68575) is still referenced from table "bar".
这个错误是可以理解的,但我该怎么解决呢?我需要一种类似于关系中的 cascade
的功能,但这是针对多态的。我在网上找不到相关的信息。我想到的办法是创建一个关系,然后在里面使用 cascade
,但这样似乎不太对。
通常应该怎么做呢?
1 个回答
6
在这种情况下,删除对象主要有两种方法。第一种是传统的ORM(对象关系映射)方式:
session.delete(some_bar)
当这个会话被刷新时,它会发出两个不同的删除语句,一个针对“bar”表,另一个针对“foo”表。不过,ORM的每个对象的delete()方法一次只能处理一个主键。
第二种方法,我觉得这就是你想要做的,类似于这样:
session.query(Foo).filter(...).delete()
使用这种删除方式,我们是在根据某些条件进行删除。有些“foo”表的行可能有指向它们的“bar”行,而有些则没有。在关系型数据库中,我们可以通过设置ON DELETE CASCADE来让数据库自动处理这些情况。SQLAlchemy允许你在外键上进行这样的配置:
ForeignKey('foo.id', ondelete="CASCADE")
上面的外键设置必须在创建表时进行,比如在metadata.create_all()
时,你会看到类似的输出:
CREATE TABLE bar (
id SERIAL NOT NULL,
foo_id INTEGER,
PRIMARY KEY (id),
FOREIGN KEY(foo_id) REFERENCES foo (id) ON DELETE CASCADE
)
然后,当你从“foo”表中删除行时,即使是在Postgresql命令行中,匹配的“bar”表中的行也会被自动删除。SQLAlchemy不会干扰这个过程,所以当你使用像query.delete()这样的操作时,这也会发生。