【问题标题】:SQLAlchemy deleting parent neither deleting child or setting child ForeignKey value to nullSQLAlchemy 删除父级既不删除子级也不将子级 ForeignKey 值设置为 null
【发布时间】:2018-12-23 06:07:26
【问题描述】:

我在 SQLAlchemy 中有各种一对多的关系。当我删除父条目时,我希望其关联的子条目也被删除。我尝试使用the docs 之后的级联属性。然而,不仅儿童没有被删除,而且他们的父 ID 也没有设置为 null,正如我在阅读 this question 和其他 SQLAlchemy 讨论后所期望的那样。

这是我的模型:

class Parent(Base):
    __tablename__ = 'parent'
    __table_args__ = {'extend_existing': True}

    id = Column(Integer, primary_key = True)

    children = relationship("Child", order_by=Child.id, backref="parent", cascade="all, delete-orphan")

    def save_to_db(self):
        db_session.add(self)
        db_session.commit()

class Child(Base):
    __tablename__ = 'child'
    __table_args__ = {'extend_existing': True}

    id = Column(Integer, primary_key = True)
    parent_id = Column(Integer, ForeignKey('parent.id')

这是我的删除端点:

    parent = Parent.find_by_id(id)
    deleted = delete(Parent.__table__, Parent.__table__.c.id==id)
    db_session.execute(deleted)
    db_session.commit()

当我第一次创建一个有孩子的父母时:

event_info = EventInfo.find_by_id(id)
ids = []
for event in event_info.events:
    ids.append(event.id)
print(str(id) + " Has: "+str(ids)) #prints: 1 has [1]

但是当我删除那个父级,然后用另一个子级创建另一个父级时:

    event_info = EventInfo.find_by_id(id)
    ids = []
    for event in event_info.events:
        ids.append(event.id)
    print(str(id) + " Has: "+str(ids)) #prints: 1 has [1,2]. When I print the information of 1, it is the information of the Child created with the original (now deleted) parent.

所以,当删除父母然后创建新的父母时,孩子们只是加起来,我最终得到了父母与许多旧父母的孩子,现在已经删除了父母。

有什么想法吗?我确定我的关系在某些方面配置错误,或者我要删除错误的内容,但我找不到与文档不一致的地方。

【问题讨论】:

    标签: python sql sqlalchemy


    【解决方案1】:

    问题是

    deleted = delete(Parent.__table__, Parent.__table__.c.id==id)
    db_session.execute(deleted)
    

    是一个核心批量操作,尽管它删除了一行。会话完全忽略了查询的影响,因此 ORM 级联不适用。如果要使用 ORM 级联,请使用会话删除实体:

    parent = Parent.find_by_id(id)
    db_session.delete(parent)
    

    此外,由于您使用的是 SQLite,并且如果您没有启用外键约束检查,则数据库允许删除子项引用的父行。如果您需要外键约束检查,您应该遵循instructions from the documentation。这个想法是发射

    PRAGMA foreign_keys=ON
    

    用于新连接。如果您希望删除级联,您也可以在数据库中添加相同的行为:

    class Child(Base):
        ...
        parent_id = Column(Integer, ForeignKey('parent.id', ondelete='CASCADE'))
    

    有时您可能希望让数据库完全处理级联,尤其是在父实体尚未填充“子”关系的情况下,在这种情况下,您可以阅读 SQLAlchemy 中的 passive deletes

    【讨论】:

      猜你喜欢
      • 2021-12-02
      • 1970-01-01
      • 1970-01-01
      • 2020-05-22
      • 2014-05-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多