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:在多表多态中删除的主要内容,如果未能解决你的问题,请参考以下文章

flask-sqlalchemy的使用

Flask-SQLAlchemy 学习总结

flask_sqlalchemy

SQLAlchemy 使用关联配置与自我的多对多关系

SQlAlchemy的增删改查

在 SQLAlchemy 中以特定格式按日期分组