我目前正在使用sqlalchemy通过flask-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抛出错误。
答案 0 :(得分:7)
删除TreatmentType
(父级)by default时,SQLAlchemy将通过设置Treatment.treatmentType_id = None
来更新子级。如您所述,您只剩下Treatment
而没有TreatmentType
。儿童记录现在是一个“孤儿”。
有两种方法可以防止在SQLAlchemy中创建孤立记录。
<强> 1。在子列上使用非NULL约束
删除TreatmentType
(父)时,默认情况下,SQLAlchemy会在执行此操作时将Treatment.treatmentType_id
(子)设置为None
(或在SQL中为null),并且你说过,你留下的Treatment
没有TreatmentType
。
对此的解决方案是将treatmentType_id
列更新为不可为空,这意味着它必须具有非空值。我们使用nullable=False
关键字来执行此操作:
treatmentType_id = db.Column(db.Integer, db.ForeignKey('treatmentType.id'), nullable=False)
现在,当执行默认级联逻辑时,SQLAlchemy会尝试设置Treatment.treatmentType_id = None
,并且由于违反了非空约束而引发IntegrityError。
<强> 2。使用passive_deletes ='all'
treatments = db.relationship('treatment', backref='treatmentType', passive_deletes='all')
当TreatmentType
被删除时,passive_deletes='all'
关系中的treatments
关键字“will disable the “nulling out” of the child foreign keys”。它基本上禁用了上面第一段中概述的默认行为。因此,当ORM尝试删除TreatmentType
而不首先设置子项Treatment.treatmentType_id = None
时,数据库将抛出IntegrityError抱怨孩子的ForeignKey引用非 - 存在的父母!
*注意:底层数据库必须支持外键才能使用此选项