Bar*_*ski 4 python polymorphism orm 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',
}
Run Code Online (Sandbox Code Playgroud)
当我尝试删除所有Foo
实例时,db.query(Foo).delete()
我得到
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".
Run Code Online (Sandbox Code Playgroud)
嗯,这个错误是有道理的,但是如何让它发挥作用呢?我需要类似cascade
关系的东西,但需要多态性。我到处都找不到它。我想到的就是建立一种关系,只是为了维持cascade
关系,但这似乎不对。
通常的做法是什么?
在这种情况下,有两种删除对象的通用方法。一种是传统的ORM方式:
session.delete(some_bar)
Run Code Online (Sandbox Code Playgroud)
当刷新此会话时,它将发出两个不同的 DELETE 语句,一个用于“bar”表,一个用于“foo”表。然而,ORM per-object delete() 一次仅适用于一个主键。
另一种方式,我认为这就是你想要做的,是这样的:
session.query(Foo).filter(...).delete()
Run Code Online (Sandbox Code Playgroud)
对于这种删除,我们会根据条件发出 DELETE。某些“foo”行可能有一个“bar”行指向它们,而其他行则没有。在关系数据库中,我们可以通过设置ON DELETE CASCADE让数据库为我们处理这个问题。SQLAlchemy 允许您在外键上将其配置为:
ForeignKey('foo.id', ondelete="CASCADE")
Run Code Online (Sandbox Code Playgroud)
上述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
)
Run Code Online (Sandbox Code Playgroud)
然后,当您从“foo”中删除行时,即使在 Postgresql 命令行中,“bar”中的匹配行也会自动删除。SQLAlchemy 不会妨碍这种情况,因此当您使用像 query.delete() 这样的东西时也会发生这种情况。