SQLALCHEMY 删除关联对象不会从父子节点中删除

Posted

技术标签:

【中文标题】SQLALCHEMY 删除关联对象不会从父子节点中删除【英文标题】:SQLALCHEMY deleting Association Object does not delete it from the parent and child 【发布时间】:2021-08-26 10:14:04 【问题描述】:

我正在尝试删除关联对象。它已从表中删除,但父对象的集合中仍有子对象。这是我的代码:

import sqlalchemy
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, Integer, ForeignKey
from sqlalchemy.orm import sessionmaker, relationship

engine = sqlalchemy.create_engine('sqlite:///:memory:')
Base = declarative_base()


class Parent(Base):
    __tablename__ = 'parent'
    id = Column(Integer, primary_key=True)
    children = relationship("Association", back_populates="parent")

    def __repr__(self) -> str:
        return f"Parent: self.id, self.children"


class Child(Base):
    __tablename__ = 'child'
    id = Column(Integer, primary_key=True)
    parents = relationship("Association", back_populates="child")

    def __repr__(self) -> str:
        return f"Child: self.id, self.parents"


class Association(Base):
    __tablename__ = 'association'
    parent_id = Column(Integer, ForeignKey('parent.id'), primary_key=True)
    child_id = Column(Integer, ForeignKey('child.id'), primary_key=True)
    child = relationship("Child", back_populates="parents")
    parent = relationship("Parent", back_populates="children")

    def __repr__(self) -> str:
        return f"Association: (self.parent); (self.child;)"


Base.metadata.create_all(engine)

Session = sessionmaker(bind=engine, autoflush=False, autocommit=False, expire_on_commit=False)
session = Session()

p = Parent()
c = Child()

session.add(p)
session.add(c)
session.commit()

association = Association(parent=p, child=c)
session.add(association)
session.commit()

assert session.query(Association).all()
assert session.query(Parent).all()[0].children
assert session.query(Child).all()[0].parents


session.delete(association)
session.commit()

assert not session.query(Association).all()
assert not session.query(Parent).all()[0].children
assert not session.query(Child).all()[0].parents

现在,当我删除一个关联对象并从表关联中查询它时,它就消失了。但是,如果我查询父对象或子对象,则关联仍在其集合字段中。我该如何配置它,所以当我删除关联对象时,该对象也会从父集合和子集合中完全删除。

【问题讨论】:

【参考方案1】:

这是因为您设置了expire_on_commit=False。这意味着无论何时提交,现有实例不会过期。

如果您将其设置为 True(默认值),您将获得您期望的行为。

详情请参阅SQLAlchemy documentation。

如果由于某种原因不需要使用expire_on_commit=True,您可以使用Session#expire 或Session#expire_all 手动使实例过期。

【讨论】:

谢谢你成功了!但是当我插入关联对象时,父子对象怎么更新了。 我对 SQLAlchemy ORM 的内部细节不是很熟悉。但据我了解,back_populates(或backref)使 SQLAlchemy 意识到任何添加都需要了解支持的关系。有人可能会争论为什么 delete 不删除引用,对此我没有明确的答案。可能值得为此专门提出一个新问题。

以上是关于SQLALCHEMY 删除关联对象不会从父子节点中删除的主要内容,如果未能解决你的问题,请参考以下文章

SQLAlchemy:直接从一对多关系中删除对象,而不使用 session.delete()

RBtree插入跟删除图解代码

SQLAlchemy 关联表(关联对象模式)引发 IntegrityError

无法使用 SQLAlchemy 删除对象实例

使用 SQLAlchemy 从反射表中删除的行

Flask SQLAlchemy 多对多关联对象错误