You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Data Integrity: Raise error on attempt to delete an object required via a Relationship #533
The default behavior of SQLAlchemy when you delete Contact is to set NULL in the invoicing_contact_id field, to avoid this, you need to set passive_deletes='all' in the relationship field in the Client model:
Now if I understand correctly, this function is supposed to raise an IntegrityError if invoicing_contact_of is not empty:
defdelete_by_id(self, entity_type: Type[sqlmodel.SQLModel], entity_id: int):
"""Deletes the entity of the given type with the given id from the database"""logger.debug(f"deleting {entity_type} with id={entity_id}")
withself.create_session() assession:
session.exec(
sqlmodel.delete(entity_type).where(entity_type.id==entity_id)
)
session.commit()
It doesn't, the deletion proceeds and the respective Client.invoicing_contact becomes missing.
Indeed! in SQLite the foreign key constraints are disabled by default (https://www.sqlite.org/foreignkeys.html, 2), you have to enable them manually. the simplest way is to listen to the connect event and enable this option:
Activity
meirdev commentedon Jan 19, 2023
The default behavior of
SQLAlchemywhen you deleteContactis to setNULLin theinvoicing_contact_idfield, to avoid this, you need to setpassive_deletes='all'in the relationship field in theClientmodel:And now you get an error when you try to delete a
Contactthat has a relationship withClient:https://docs.sqlalchemy.org/en/20/orm/relationship_api.html#sqlalchemy.orm.relationship.params.passive_deletes
clstaudt commentedon Jan 19, 2023
@meirdev Thanks for the suggestion, it was quite difficult to find documentation on this.
However, I am not getting the desired behavior.
I have modified the model as follows:
Now if I understand correctly, this function is supposed to raise an
IntegrityErrorifinvoicing_contact_ofis not empty:It doesn't, the deletion proceeds and the respective
Client.invoicing_contactbecomes missing.meirdev commentedon Jan 19, 2023
Works for me:
clstaudt commentedon Jan 19, 2023
Strange. Will run the minimal example to investigate. But does it matter that you are using PostgreSQL and I am using SQLite?
meirdev commentedon Jan 20, 2023
Indeed! in SQLite the foreign key constraints are disabled by default (https://www.sqlite.org/foreignkeys.html, 2), you have to enable them manually. the simplest way is to listen to the
connectevent and enable this option:clstaudt commentedon Jan 20, 2023
@meirdev Now the
IntegrityErroris raised. However, the logic is bidirectional:If I try to delete a
ClientI get also anIntegrityError. But this should be allowed.meirdev commentedon Jan 20, 2023
I think the error came from something else, in my sample code if I try to delete
Clientthere are no errors.clstaudt commentedon Feb 9, 2023
@meirdev I can verify that our minimal examples are working fine. However, in the context of the entire data model, this is not working.
Basic idea of the data model:
ProjectrequiresContractrequiresClientrequiredContact.Trying to delete a
Clientraisesand so does trying to delete a
ContractorProject.It seems that by adding just this to the
Contactmodel:... I have made every object with a path to an existing
Contactundeletable.The "FOREIGN KEY contraint failed" message is also unhelpful because it doesn't tell us any details. Is there a way to get more info?
YuriiMotov commentedon Aug 7, 2025
There is a dedicated section in current version of docs: Cascade Delete Relationships
@clstaudt, do you think we can close this issue now?
YuriiMotov commentedon Aug 16, 2025
This section of docs describes exactly what is needed: https://sqlmodel.tiangolo.com/tutorial/relationship-attributes/cascade-delete-relationships/#ondelete-with-restrict