如果删除了孩子,则删除父母

时间:2018-08-27 18:31:44

标签: python sqlalchemy one-to-many cascading-deletes

如果子表中的关联行已删除,我想删除父行。

class Child(Base):
    __tablename__ = "children"

id = Column(Integer, primary_key=True)
parent_id = Column(Integer, ForeignKey("parents.id", ondelete='CASCADE'))

class Parent(Base):
    __tablename__ = "parents"
id = Column(Integer, primary_key=True)
child = relationship(Child, backref="parent", passive_deletes=True)

如果我删除孩子

child_obj = session.query(Child).first()
session.delete(child_obj)
session.commit()

它确实删除了子对象obj,但父对象保持原样。我也想使用级联删除父级。

3 个答案:

答案 0 :(得分:1)

您可以阅读以下主题: Linking Relationships with Backref

class User(Base):
    __tablename__ = 'user'
    id = Column(Integer, primary_key=True)
    name = Column(String)

    addresses = relationship("Address", backref="user")

class Address(Base):
    __tablename__ = 'address'
    id = Column(Integer, primary_key=True)
    email = Column(String)
    user_id = Column(Integer, ForeignKey('user.id'))

您可以在子类中定义它:

parent = relationship(Parent, backref=backref("children", cascade="all,delete"))

答案 1 :(得分:0)

您所指的行为有点简单。但是一旦应用程序变大,您将需要更复杂的方法。我个人为每个类实现一个静态方法remove。它需要id和其他任何必要的参数才能知道删除方案。

已经给出了答案...但这只是效率低下的方法,仅举一个例子。

class Child(Base):
    __tablename__ = "children"
    id = Column(Integer, primary_key=True)
    parent_id = Column(Integer, ForeignKey("parents.id", ondelete='CASCADE'))
    
    @staticmethod
    def remove(_id_):
        child = Child.query().get(_id_)
        Parent.remove(child.parent_id)
        session.delete(child)

class Parent(Base):
    __tablename__ = "parents"
    id = Column(Integer, primary_key=True)
    child = relationship(Child, backref="parent", passive_deletes=True)

    @staticmethod
    def remove(_id_):
        parent = parent.query().get(_id_)
        session.delete(parent)

例如,如果您在Column类中添加了一个名为is_old的{​​{1}}-那是二进制整数0或1,并且想要删除其中的Child具有parent的{​​{1}},这将是非常容易的任务。

答案 2 :(得分:0)

对于简单的 * 情况,您可以通过创建listener来做到这一点,该拦截器拦截Child实例的删除,如果没有其他子代,则删除父代。

import sqlalchemy as sa

@sa.event.listens_for(sessionmaker, 'persistent_to_deleted')
def intercept_persistent_to_deleted(session, object_):
    # We are only interested in instances of Child.
    if not isinstance(object_, Child):
        return
    p = object_.parent
    # Handle null parents.
    if p is None:
        return
    cs = session.query(Child).filter(Child.parent == p).count()
    if cs == 0:
        session.delete(p)

* 我建议您进行彻底的测试,看看您的代码是否在执行删除会话的工作,例如在同一会话中与删除的孩子的父母一起创建新的孩子。监听器在这种情况下起作用:

c = session.query(Child).first()
p = c.parent
session.delete(c)
c1 = Child(parent=p)
session.add(c1)
session.commit()

但尚未经过任何更复杂的测试。