Flask中的(pymysql.err.IntegrityError)(1451,'无法删除或更新父行:外键约束失败...')
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Flask中的(pymysql.err.IntegrityError)(1451,'无法删除或更新父行:外键约束失败...')相关的知识,希望对你有一定的参考价值。
我知道标题中有很多关于错误的问题,但我找不到合适的解决方案。我的问题是,当使用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', )
为什么
在你的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或使用一些工具。
以上是关于Flask中的(pymysql.err.IntegrityError)(1451,'无法删除或更新父行:外键约束失败...')的主要内容,如果未能解决你的问题,请参考以下文章