SQLAlchemy:在多表多态中删除
Posted
技术标签:
【中文标题】SQLAlchemy:在多表多态中删除【英文标题】:SQLAlchemy: deleting in multitable polymorphism 【发布时间】:2014-05-20 06:56:12 【问题描述】:我有这样的模型层次结构:
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】:在这种情况下,有两种删除对象的一般方法。一种是传统的ORM方式:
session.delete(some_bar)
当这个会话被刷新时,它将发出两个不同的 DELETE 语句,一个用于“bar”表,一个用于“foo”表。但是,ORM per-object delete() 一次只能对一个主键起作用。
我认为您正在尝试做的另一种方式是这样的:
session.query(Foo).filter(...).delete()
使用这种删除,我们会跨标准发出 DELETE。一些“foo”行可能有一个“bar”行指向它们,而另一些则没有。在关系数据库中,我们可以通过设置ON DELETE CASCADE 让数据库为我们处理这个问题。 SQLAlchemy 允许您在 ForeignKey 上将其配置为:
ForeignKey('foo.id', ondelete="CASCADE")
上述FK必须发生在表创建操作中;比如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() 之类的东西时也会发生这种情况。
【讨论】:
以上是关于SQLAlchemy:在多表多态中删除的主要内容,如果未能解决你的问题,请参考以下文章