[英]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):無法刪除或更新父行,外鍵約束失敗(
test
。person
,約束person_ibfk_1
外鍵(parent_id
)參考person
(id
) )
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-update和merge 。 在此默認配置中,當通過將子代的外鍵設置為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.