我知道标题中有很多关于错误的问题,但我找不到合适的解决方案。我的问题是,在使用Session.delete()
删除行时,它正在抛出
sqlalchemy.exc.IntegrityError: (pymysql.err.IntegrityError) (1451, 'Cannot delete or update a parent row: a foreign key constraint fails (`transport`.`driver`, CONSTRAINT `driver_ibfk_1` FOREIGN KEY (`owner_id`) REFERENCES `truckcompany` (`id`))') [SQL: 'DELETE FROM truckcompany WHERE truckcompany.id = %(id)s'] [parameters: {'id': 4}]
型号:
class Truck_company(Base):
__tablename__ = 'truckcompany'
id = Column(BigInteger, primary_key=True)
class Driver(Base):
__tablename__ = 'driver'
id = Column(BigInteger, primary_key=True)
owner_id = Column(BigInteger, ForeignKey('truckcompany.id'))
owner = relationship(Truck_company)
删除失败的视图:
@app.route('/values/deleteuser/<int:id>', methods=['POST', 'GET'])
def delete_truck(id):
value_truckcompany = sqlsession.query(Truck_company).filter(Truck_company.id == id).first()
if value_truckcompany:
sqlsession.delete(value_truckcompany)
sqlsession.commit()
return redirect('/static/truckcompanyview', )
答案 0 :(得分:2)
在Driver
模型中,有一个引用Truck_company
的外键约束:
class Driver(Base):
...
owner_id = Column(BigInteger, ForeignKey('truckcompany.id'))
您已省略ON DELETE操作,因此MySQL defaults to RESTRICT。此外,没有SQLAlchemy ORM与级联的关系会删除相关的驱动程序。因此,当您尝试在视图中删除卡车公司时,数据库会阻止您执行此操作,因为您违反了外键约束,换句话说referential integrity。这是你如何建模数据库的问题,而不是Flask等。
最重要的事情 - 当你创建你的模型时 - 是决定当你删除一个有相关驱动程序的卡车公司时你想要发生什么。您的选择包括但不限于:
owner_id
设置为NULL,有效地将其分离。如果在父级的默认配置中存在ORM关系,那么这就是SQLAlchemy所做的。这也是一个完全有效的解决方案,可以限制删除带子节点的父行,正如您已经隐式完成的那样。
您已在评论中表示您要删除相关的驱动程序。快速解决方案是手动发出DELETE:
# WARNING: Allowing GET in a data modifying view is a terrible idea.
# Prepare yourself for when Googlebot, some other spider, or an overly
# eager browser nukes your DB.
@app.route('/values/deleteuser/<int:id>', methods=['POST', 'GET'])
def delete_truck(id):
value_truckcompany = sqlsession.query(Truck_company).get(id)
if value_truckcompany:
sqlsession.query(Driver).\
filter_by(owner=value_truckcompany).\
delete(synchronize_session=False)
sqlsession.delete(value_truckcompany)
sqlsession.commit()
return redirect('/static/truckcompanyview', )
另一方面,这仅修复了这一个位置。如果您确定Driver
没有Truck_company
没有意义,则可以alter the foreign key constraint包含ON DELETE CASCADE,并在相关的SQLAlchemy ORM关系中使用passive deletes:
class Truck_company(Base):
...
# Remember to use passive deletes with ON DELETE CASCADE
drivers = relationship('Driver', passive_deletes=True)
class Driver(Base):
...
# Let the DB handle deleting related rows
owner_id = Column(BigInteger, ForeignKey('truckcompany.id',
ondelete='CASCADE'))
或者你可以将它留给SQLAlchemy ORM级别级联来删除相关对象,但似乎你在过去遇到了一些问题。请注意,SQLAlchemy cascades定义operation on the parent应如何传播给其子级,因此您在父方关系中定义delete
和可选delete-orphan
,或者一对多的一面:
class Truck_company(Base):
...
# If a truck company is deleted, delete the related drivers as well
drivers = relationship('Driver', cascade='save-update, merge, delete')
在您当前的模型中,您从Truck_company
到Driver
定义了无关系,因此不会发生级联。
请注意修改Driver
,例如:
class Driver(Base):
...
owner_id = Column(BigInteger, ForeignKey('truckcompany.id',
ondelete='CASCADE'))
将不神奇地迁移现有的数据库表及其约束。如果您希望采用该路线,则必须migrate manually或使用某种工具。