【问题标题】:SQLAlchemy One-To-Many: Constrain Parent to have At Least One ChildSQLAlchemy 一对多:约束父母至少有一个孩子
【发布时间】:2019-05-06 15:56:34
【问题描述】:

假设我有简单的 SQLAlchemy 映射:

class Parent(db.Model)
    id = db.Column(db.Integer, primary_key=True)
    children = db.relationship('Child', back_populates='parent')

class Child(db.Model)
    id = db.Column(db.Integer, primary_key=True)
    parent_id = db.Column(db.Integer, db.ForeignKey('parent.id'), nullable=False)
    parent = db.relationship('Parent', back_populates='children')

在这种形式中,它是一个One(Parent)-to-Many(Children)

由于nullable 标志,每个Child 必须有一个Parent,否则会引发IntegrityError。 [注意默认不级联'deletes'或'orphan-deletes',确保当父级被删除时,其子级也被删除,因此错误]

但是,当Parent零个孩子时,我想提出一个IntegrityError。 即:

  • 禁止创建新的Parent 而不创建并指定至少一个Child
  • 禁止删除 Parents children 集合中的最后一个 Child

在 Postgres(以及开发中的 SQLite 3)中有什么方法可以做到这一点?

【问题讨论】:

    标签: python sqlalchemy one-to-many


    【解决方案1】:

    要使其与数据库无关,您可以在插入之前使用 sqlalchemy 事件来检查父母:

    from sqlalchemy import event
    
    
    @event.listens_for(Parent, 'before_insert')
    @event.listens_for(Parent, 'before_update')
    def receive_before_insert_or_update(mapper, connection, parent):
    
        if not parent.children:
            # you should probably use your own exception class here
            raise IntegrityError("Parent without children not allowed")
    

    这将防止插入或更新有/没有孩子的父母。您可以对before_delete 事件使用相同的模式来防止删除子项。

    【讨论】:

    • 这有什么缺点吗?如果 ORM 事件在特殊事件中丢失或未触发怎么办?虽然我已经实现了您的解决方案,但我仍然想知道是否有一个数据库配置可以通过一些底层约束自然地强制执行此操作?
    • 好吧,我不认为 sqlalchemy 会“错过”这些事件,但你说得对,数据库以这种方式并没有真正强制父母有一个孩子。
    猜你喜欢
    • 2016-11-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-02-04
    相关资源
    最近更新 更多