簡體   English   中英

SQLAlchemy FK ondelete不會限制

[英]SQLAlchemy FK ondelete does not RESTRICT

我建立了自我參照關系。 一個人可以有一個單親父母(或無),一個人可以有多個孩子(或無)。

因此允許將NULL用作FK:

class Person(db.Model):
    id        = db.Column(db.Integer, primary_key=True)
    parent_id = db.Column(db.Integer, db.ForeignKey('person.id', ondelete='RESTRICT'))
    parent    = db.relationship('Person', remote_side=[id], back_populates='children')
    children  = db.relationship('Person', back_populates='parent')

但是,我想禁止刪除作為父母的人。 所以我加入了ondelete='RESTRICT'子句,但是它沒有任何作用。 刪除父級后,parent_id列仍設置為NULL。

(請注意,我的SQLite連接將編譯指示外鍵約束轉換為ON)

為什么在刪除父級時數據庫不引發錯誤,因此以其作為外鍵的子級列對此進行了限制?

Sqlalchemy在數據庫有機會評估外鍵約束之前使子行為空。 如果在關系上添加passive_deletes=True ,則passive_deletes=True 不會嘗試管理相關實體的刪除,而只是讓數據庫根據您的配置方式來執行此操作。 在刪除父級之前,不會先發出選擇來填充關系。 設置為True仍將導致會話中已有子對象的FK列設置為NULL

此配置:

class Person(db.Model):
    id        = db.Column(db.Integer, primary_key=True)
    parent_id = db.Column(db.Integer, db.ForeignKey('person.id', ondelete='RESTRICT'))
    parent    = db.relationship('Person', remote_side=[id], back_populates='children')
    children  = db.relationship('Person', back_populates='parent', passive_deletes=True)


if __name__ == '__main__':
    with app.app_context():
        db.drop_all()
        db.create_all()
        parent = Person()
        db.session.add(parent)
        child = Person(parent=parent)
        db.session.commit()
        db.session.delete(parent)
        db.session.commit()

籌款:

sqlalchemy.exc.IntegrityError:(mysql.connector.errors.IntegrityError)1451(23000):無法刪除或更新父行,外鍵約束失敗( testperson ,約束person_ibfk_1外鍵( parent_id )參考personid ) )

if __name__ == '__main__':
    with app.app_context():
        db.drop_all()
        db.create_all()
        parent = Person()
        db.session.add(parent)
        child = Person(parent=parent)
        db.session.commit()
        db.session.query(Person).all()  # reload the people into the session before deleting parent
        db.session.delete(parent)
        db.session.commit()

...仍將使子級的parent_id字段為null,即使使用passive_deletes=True 因此, passive_deletes='all'是必經之路。

您的外鍵約束設置看起來正確,但是您的ORM關系沒有顯式的級聯配置,因此它們使用的是默認值save-updatemerge 在此默認配置中,當通過將子代的外鍵設置為NULL來刪除父代時, children關系取消其關聯。 我認為您在這種情況下應該使用passive_deletes='all' (請參閱有關刪除級聯的注釋)來在刪除父級時禁用任何ORM級別的級聯,以便數據庫在刷新時可以防止刪除:

class Person(db.Model):
    id        = db.Column(db.Integer, primary_key=True)
    parent_id = db.Column(db.Integer, db.ForeignKey('person.id', ondelete='RESTRICT'))
    parent    = db.relationship('Person', remote_side=[id], back_populates='children')
    children  = db.relationship('Person', back_populates='parent', passive_deletes='all')

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM