Fal*_*iss 2 python sqlalchemy flask
我知道标题中的错误有很多问题,但我找不到合适的解决方案。我的问题是,在使用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)
Run Code Online (Sandbox Code Playgroud)
删除失败的视图:
@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', )
Run Code Online (Sandbox Code Playgroud)
在您的Driver模型中有一个外键约束引用Truck_company:
class Driver(Base):
...
owner_id = Column(BigInteger, ForeignKey('truckcompany.id'))
Run Code Online (Sandbox Code Playgroud)
您已省略 ON DELETE 操作,因此 MySQL默认为 RESTRICT。此外,SQLAlchemy ORM 与会删除相关驱动程序的级联没有关系。因此,当您尝试删除视图中的卡车公司时,数据库会阻止您这样做,因为您违反了外键约束,换句话说就是参照完整性。这是您如何对数据库进行建模的问题,而不是 Flask 等。
当您创建模型时,要做的最重要的事情是决定当您删除具有相关司机的卡车公司时您希望发生什么。您的选择包括但不限于:
owner_id为 NULL,有效地分离它们。这就是 SQLAlchemy 所做的,如果 ORM 关系存在于父级的默认配置中。它也是限制删除带有子行的父行的完全有效的解决方案,正如您隐式所做的那样。
您已在评论中表示要删除相关驱动程序。一个快速的解决方案是手动发出 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', )
Run Code Online (Sandbox Code Playgroud)
另一方面,这仅修复了这个位置。如果您决定 aDriver没有它的意义Truck_company,您可以更改外键约束以包含 ON DELETE CASCADE,并在相关的 SQLAlchemy ORM 关系中使用被动删除:
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'))
Run Code Online (Sandbox Code Playgroud)
或者,您可以将它留给 SQLAlchemy ORM 级级联以删除相关对象,但过去似乎您遇到了一些问题。请注意,SQLAlchemy 级联定义了对父级的操作应如何传播到其子级,因此您可以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')
Run Code Online (Sandbox Code Playgroud)
在您当前的模型中,您没有从Truck_companyto定义关系Driver,因此不会发生级联。
注意修改Driver如:
class Driver(Base):
...
owner_id = Column(BigInteger, ForeignKey('truckcompany.id',
ondelete='CASCADE'))
Run Code Online (Sandbox Code Playgroud)
会不会神奇地迁移现有的数据库表和它的约束。如果您希望采用该路线,则必须手动迁移或使用某些工具。
| 归档时间: |
|
| 查看次数: |
3421 次 |
| 最近记录: |