3

I'm aware that there are many questions about the error in the title, but I could't find a suitable solution. My problem is that while deleting a row using Session.delete() it's throwing

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}]

Models:

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)

The view with the failing delete:

@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', )
Ilja Everilä
  • 50,538
  • 7
  • 126
  • 127
Falcon bliss
  • 71
  • 2
  • 11
  • 1
    I think you have one more table that refers to truckcompany table ? – Vikas Periyadath Mar 06 '18 at 07:26
  • Can give me example idea. – Falcon bliss Mar 06 '18 at 07:27
  • 1
    *Read the error carefully*. You have a row in `driver` referencing the row in `truckcompany` that you're trying to delete. You'll have to think about what you'd like to happen in that case. Do you want to delete the drivers also? Or set their `owner_id` to NULL? And as always, provide a [mcve]. You've left out your driver model, for example. Usually it also helps if you include which DB you are using, though in this case it's obvious from the error message. – Ilja Everilä Mar 06 '18 at 07:34
  • I just update the orm.py ,if you help me now sir. – Falcon bliss Mar 06 '18 at 07:45
  • ok..,but ,how to delete row entire row in truckcompany. at the same time in driver table also delete the . i used to delete row using cascade='all,delete'. but sometimes its working sometimes its not working. what should i do? – Falcon bliss Mar 06 '18 at 08:00
  • 1
    As to why this happens: ["For an ON DELETE or ON UPDATE that is not specified, the default action is always RESTRICT. "](https://dev.mysql.com/doc/refman/5.7/en/create-table-foreign-keys.html) Either alter the DB foreign key constraint to use ON DELETE CASCADE and modify your SQLA model to reflect that, manually delete `Driver`s related to the `Truck_company` to be deleted, or use the SQLA cascades (that you have tried already). – Ilja Everilä Mar 06 '18 at 08:05
  • I am unable to understand .can you give any example demo. – Falcon bliss Mar 06 '18 at 08:12
  • where you are using owner_id ? – Vikas Periyadath Mar 06 '18 at 08:25
  • using owner_id in drvier table. – Falcon bliss Mar 06 '18 at 09:14
  • @Falconbliss Do you want the corresponding driver records to get deleted, if truck company record gets deleted? First decide this, then you can follow as IIja Everila suggests – Sachin G. Mar 06 '18 at 09:52
  • truck company records not deleted . when i click the delete button that values will be deleted permanently. then,what should i do? to delete the record permanently. – Falcon bliss Mar 06 '18 at 09:55

1 Answers1

6

Why

In your Driver model there's a foreign key constraint referencing Truck_company:

class Driver(Base):
    ...
    owner_id = Column(BigInteger, ForeignKey('truckcompany.id'))

You've omitted the ON DELETE action, so MySQL defaults to RESTRICT. Also there are no SQLAlchemy ORM relationships with cascades that would delete the related drivers. So when you try to delete the truck company in the view, the DB stops you from doing that, because you'd violate your foreign key constraint and in other words referential integrity. This is an issue with how you've modeled your DB, not Flask etc.

What can I do

The most important thing to do – when you're creating your model – is to decide what would you like to happen when you delete a truck company with related drivers. Your options include, but are not limited to:

  1. Deleting the drivers also.
  2. Setting their owner_id to NULL, effectively detaching them. This is what SQLAlchemy does, if an ORM relationship is present in its default configuration in the parent.

It is also a perfectly valid solution to restrict deleting parent rows with children, as you've implicitly done.

You've expressed in the comments that you'd like to remove the related drivers. A quick solution is to just manually issue a 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', )

This on the other hand fixes this one location only. If you decide that a Driver has no meaning without its Truck_company, you could alter the foreign key constraint to include ON DELETE CASCADE, and use passive deletes in related SQLAlchemy ORM relationships:

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'))

Alternatively you could leave it to the SQLAlchemy ORM level cascades to remove related objects, but it seems you've had some problems with that in the past. Note that the SQLAlchemy cascades define how an operation on the parent should propagate to its children, so you define delete and optionally delete-orphan on the parent side relationship, or the one-to-many side:

class Truck_company(Base):
    ...
    # If a truck company is deleted, delete the related drivers as well
    drivers = relationship('Driver', cascade='save-update, merge, delete')

In your current model you have no relationship defined from Truck_company to Driver, so no cascades take place.


Note that modifying Driver such as:

class Driver(Base):
    ...
    owner_id = Column(BigInteger, ForeignKey('truckcompany.id',
                                             ondelete='CASCADE'))

will not magically migrate the existing DB table and its constraints. If you wish to take that route, you'll have to either migrate manually or using some tool.

Ilja Everilä
  • 50,538
  • 7
  • 126
  • 127
  • 1
    it's working ok. but ,deleting recorde one or two .after that showing sqlalchemy.exc.IntegrityError: (pymysql.err.IntegrityError) (1451, 'Cannot delete or update a parent row: a foreign key constraint fails (`transport`.`driverallocation`, CONSTRAINT `driverallocation_ibfk_1` FOREIGN KEY (`driver_id`) REFERENCES `driver` (`id`))') [SQL: 'DELETE FROM driver WHERE driver.id = %(id)s'] [parameters: {'id': 2}] – Falcon bliss Mar 08 '18 at 12:16
  • 1
    it is allowing one or two records. – Falcon bliss Mar 08 '18 at 12:17
  • 1
    That error looks familiar doesn't it? It's the same thing all over again: a foreign key in table *driverallocation* restricts you from deleting the driver. Note that you did not include that table in your post originally. Just go through the same thinking process as before. What should happen to driver allocations, when a driver is removed (prolly delete as well). – Ilja Everilä Mar 08 '18 at 13:19
  • 1
    just i tried to delete the first row .but ,it's not deleting and remaing rows are deleting why? – Falcon bliss Mar 08 '18 at 13:22
  • 1
    Again, I do not have your tables, nor your data. I cannot know. Please stop using a single question and answer as a generic support service. – Ilja Everilä Mar 08 '18 at 13:33