django-postgres-extra
django-postgres-extra copied to clipboard
Add support for native cascading deletes
Django emulates cascades by fetching all the related objects and deleting them instead of relying on the DB to do this.
One likely pain point for this is figuring out the Right Thing to do with regard to signals. Django itself will call the pre_delete
and post_delete
handlers for each object on cascade deletes. That really wouldn't be reasonable with db-level cascades. I'm not sure what the best way to handle that is, or if perhaps there's a way to throw an error if there are registered post_delete
signals combined with the cascade deletes, so that at least it will fail loudly.
That's a very good point. One of the things you'd most likely have to give up on with native DB cascading is Django signals. I always envisioned this as a feature that provides an alternative method to bulk to delete records. With a certain price to pay; not having signals.
One way of doing this would be to provide a custom query set method such as:
MyModel.objects.delete_native_cascade()
The name in the example above is not greatest, but it makes a clear distinction between Django's standard delete
method and a native delete.
It might also be possible to ask the database to return the primary keys of the records that are going to be deleted. That would allow us to to still invoke some kind of signal.
Anyhow, any ideas on how to implement this feature are more than welcome. I apreciate you taking the time to think about this. It certainely is something that we have to think about.
Maybe it would be a good option to add a custom foreign key definition that creates FK on the database with Postgres specific options, like CASCADE deletion (ON DELETE CASCADE
in the field definition on the database level).
let's name it:
PostgresForeginKey
with can be called with parameter PostgresForeginKey(native_on_delete=CASCADE)
By that, the Database will handle cascade deletions.
Next, we can add an implementation of the delete_native_cascade
method which generates a simple bulk DELETE query. But before it generates it, it checks whether the related model point to it via our PostgresFields, if not, then we can raise an exception (operation not supported).