【问题标题】:Delete parent object when all children have been deleted in sqlalchemy在 sqlalchemy 中删除所有子对象后删除父对象
【发布时间】:2018-12-27 09:17:36
【问题描述】:

假设我有以下关系:

Reference(slide_id, group_id) 其中引用是幻灯片和组的关联。

一张幻灯片可用于多个引用(具有不同的组):主键是slide_id + group_id,必须是唯一的。

我希望在删除指向的组或幻灯片时删除所有引用。 我通过在关系的 backref 中添加级联来做到这一点:

# definition of Reference model

slide = db.relationship(
    Slide,
    backref=db.backref('references', cascade='all, delete, delete-orphan')
)

group = db.relationship(
    Group,
    backref=db.backref('references', cascade='all, delete, delete-orphan')
)

我还希望删除引用的组或幻灯片,只要我删除一个引用并且没有其他引用使用该组和/或幻灯片。

我曾考虑在需要时使用@listens_for(Reference, 'after_delete') 手动删除父母。我也尝试了关系中的属性组合,但我不确定如何解决这个问题。

【问题讨论】:

    标签: python orm sqlalchemy associations relationship


    【解决方案1】:

    我认为@listens_for 的想法还不错。你只需要听Referencebefore_delete。下面是一个可以提供帮助的示例。

    class Slide(db.Model):
        __tablename__ = 'slide'
    
        id = db.Column(db.Integer, primary_key=True)
        children = db.relationship('Reference')
        references = db.relationship('Reference', back_populates='slide')
    
    
    class Group(db.Model):
        __tablename__ = 'group'
    
        id = db.Column(db.Integer, primary_key=True)
        references = db.relationship('Reference', back_populates='group')
    
    
    class Reference(db.Model):
        __tablename__ = 'reference'
    
        id = db.Column(db.Integer, primary_key=True)
        slide_id = db.Column(db.Integer, db.ForeignKey('slide.id'))
        group_id = db.Column(db.Integer, db.ForeignKey('group.id'))
        group = db.relationship('Group', back_populates='references')
        slide = db.relationship('Slide', back_populates='references')
    
    
    @event.listens_for(Reference, 'before_delete')
    def delete_reference(mapper, connection, target):
        # after_flush used for consistent results
        @event.listens_for(Session, 'after_flush', once=True)
        def receive_after_flush(session, context):
            # just do here everything what you need...
            # if our preference slide is the last one
            if target.slide and not target.slide.references:
                print('add slide with id = %s to delete' % target.slide.id)
                session.delete(target.slide)
            # if our preference group is the last one
            if target.group and not target.group.references:
                session.delete(target.group)
                print('add group with id = %s to delete' % target.group.id)
    

    让我们检查一下:

    # clear tables
    Reference.query.delete()
    Group.query.delete()
    Slide.query.delete()
    # create one reference with only 1 group and only 1 slide
    reference = Reference(group=Group(), slide=Slide())
    db.session.add(reference)
    db.session.commit()
    
    print('reference with id %s was created. slide_id = %s, group_id = %s' % (
        reference.id, reference.slide_id, reference.group_id
    ))
    reference = Reference.query.filter_by(id=reference.id).first()
    print('add reference with id = %s to delete' % reference.id)
    db.session.delete(reference)
    db.session.commit()
    print('amount references after delete: %s' % Reference.query.all())
    
    
    # create 2 references but with the same group and slide
    group = Group()
    slide = Slide()
    reference = Reference(group=group, slide=slide)
    reference2 = Reference(group=group, slide=slide)
    db.session.add(reference)
    db.session.add(reference2)
    db.session.commit()
    print('reference with id %s was created. slide_id = %s, group_id = %s' % (
        reference.id, reference.slide_id, reference.group_id
    ))
    print('reference2 with id %s was created. slide_id = %s, group_id = %s' % (
        reference2.id, reference2.slide_id, reference2.group_id
    ))
    
    reference = Reference.query.filter_by(id=reference.id).first()
    print('add reference with id = %s to delete' % reference.id)
    db.session.delete(reference)
    print('amount references after delete: %s' % Reference.query.all())
    db.session.commit()
    

    您会看到在第一种情况下PreferenceGroupSlide 已被删除。因为其他PreferenceGroupSlide 无关。但在第二种情况下,您会看到只有 Preference 被删除:

    reference with id 76 was created. slide_id = 65, group_id = 65
    add reference with id = 76 to delete
    add slide with id = 65 to delete
    add group with id = 65 to delete
    amount references after delete: []
    reference with id 77 was created. slide_id = 66, group_id = 66
    reference2 with id 78 was created. slide_id = 66, group_id = 66
    add reference with id = 77 to delete
    # with slide_id = 66, group_id = 66
    amount references after delete: [<Reference 78>]
    

    希望这会有所帮助。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-08-26
      • 2019-11-25
      • 2021-07-23
      • 2021-11-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多