2017-03-23 42 views
1
孤兒

我目前正在建設通過燒瓶SQLAlchemy的使用SQLAlchemy的數據模型防止刪除父行,如果它的孩子將在SQLAlchemy的

數據庫是

我有麻煩時,PostgreSQL服務器上從具有關係的表中刪除行。在這種情況下,我有一些治療類型和一種治療方法。該治療具有指定的單一治療類型。

只要我有一個或多個治療分配了特定的治療類型,我希望治療類型不能被刪除。現在它在我嘗試時被刪除。

我有以下型號:

class treatment(db.Model): 
    __tablename__ = 'treatment' 
    __table_args__ = (db.UniqueConstraint('title', 'tenant_uuid'),) 

    id = db.Column(db.Integer, primary_key=True) 
    uuid = db.Column(db.String(), nullable=False, unique=True) 
    title = db.Column(db.String(), nullable=False) 
    tenant_uuid = db.Column(db.String(), nullable=False) 

    treatmentType_id = db.Column(db.Integer, db.ForeignKey('treatmentType.id')) 
    riskResponse_id = db.Column(db.Integer, db.ForeignKey('riskResponse.id')) 

class treatmentType(db.Model): 
    __tablename__ = 'treatmentType' 
    __table_args__ = (db.UniqueConstraint('title', 'tenant_uuid'),) 

    id = db.Column(db.Integer, primary_key=True) 
    uuid = db.Column(db.String(), nullable=False, unique=True) 
    title = db.Column(db.String(), nullable=False) 
    tenant_uuid = db.Column(db.String(), nullable=False) 

    treatments = db.relationship('treatment', backref='treatmentType', lazy='dynamic') 

我可以在我的「刪除」認爲,檢查指定的治療,刪除處理類型之前建立一些邏輯,但在我看來,這應該是一個標準功能的關係數據庫。換句話說,我必須做錯事。

我刪除處理類型,像這樣:

entry = treatmentType.query.filter_by(tenant_uuid=session['tenant_uuid']).all() 
    try: 
     db.session.delete(entry) 
     db.session.commit() 
     return {'success': 'Treatment Type deleted'} 
    except Exception as E: 
     return {'error': unicode(E)} 

正如我說,這是我能夠刪除處理類型之前做檢查,但我寧願有,如果有關係SQLAlchemy的拋出一個錯誤刪除前的問題。

回答

2

當刪除TreatmentType(父),by default時,SQLAlchemy將通過設置Treatment.treatmentType_id = None來更新孩子。正如你所說,你留下了Treatment沒有TreatmentType。孩子的記錄現在是一個「孤兒」。

有兩種方法可以防止在SQLAlchemy中創建孤立記錄。

1.對孩子列

當刪除TreatmentType(父),默認情況下,SQLAlchemy的將設置Treatment.treatmentType_id(孩子),以None使用非NULL約束(或SQL空)的時候您執行此操作,如您所述,您將留下一個Treatment而不需要TreatmentType

對此的解決方案是將treatmentType_id列更新爲不可爲空,這意味着它必須具有非空值。我們使用nullable=False關鍵字做到這一點:

treatmentType_id = db.Column(db.Integer, db.ForeignKey('treatmentType.id'), nullable=False) 

現在,默認的級聯邏輯執行時,SQLAlchemy的嘗試設置Treatment.treatmentType_id = NoneIntegrityError上升,由於非空約束被違反。

2.使用passive_deletes = '全部'

treatments = db.relationship('treatment', backref='treatmentType', passive_deletes='all') 

TreatmentType得到刪除,在treatments關係 「will disable the 「nulling out」 of the child foreign keys」 的passive_deletes='all'關鍵字。它基本上禁用了上面第一段中概述的默認行爲。所以,當ORM試圖刪除TreatmentType而不是首先設置孩子的Treatment.treatmentType_id = None時,數據庫會拋出IntegrityError抱怨孩子的ForeignKey引用了一個不存在的父親!

*注:底層的數據庫必須支持外鍵使用此選項

+0

謝謝Aelfinn 這是在這種情況下要走的路。目前還有很多類似的情況。 但是當相關項目是可選項時該怎麼辦? –

+0

答案已經用'passive_deletes ='all''關鍵字更新 - 這應該會讓你找到你想要的。 –

相關問題