2017-03-23 41 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''关键字更新 - 这应该会让你找到你想要的。 –

相关问题