Soft delete for Django ORM, with support for undelete. Supports Django 2.0+
This project provides undelete of soft-deleted objects, along with proper undeletion of related objects.
Inspired by http://codespatter.com/2009/07/01/django-model-manager-soft-delete-how-to-customize-admin/
- Django 1.8+
- django.contrib.contenttypes
pip install django-softdelete
There are simple templates files in templates/
. You will need to add Django's
egg loader to use the templates as is, that would look something like this:
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': '/path/to/my/templates',
'OPTIONS': {
'loaders': (
'django.template.loaders.filesystem.Loader',
'django.template.loaders.app_directories.Loader',
),
}
},
]
Add the project softdelete
to your INSTALLED_APPS
for
through-the-web undelete support.
INSTALLED_APPS = (
...
'django.contrib.contenttypes',
'softdelete',
)
- Run
django-admin migrate
- For the models that you want soft delete to be implemented in, inherit from the
SoftDeleteObject
withfrom softdelete.models import SoftDeleteObject
. Something likeMyCustomModel(SoftDeleteObject, models.Model)
. This will add an extradeleted_at
field which will appear in the admin form after deleting/undeleting the object - If you have a custom manager also make sure to inherit from the
SoftDeleteManager
. - After that you can test it by deleting and undeleting objects from your models. Have fun undeleting :)
Name | Default | Description |
---|---|---|
SOFTDELETE_CASCADE_ALLOW_DELETE_ALL |
True | Setting to confirm if the logic for deleting related entities should fall back to deleting all model entities in the event of an exception being raised when calling delete |
Central to the ability to undelete a soft-deleted model is the concept of changesets. When you soft-delete an object, any objects referencing it via a ForeignKey, ManyToManyField, or OneToOneField will also be soft-deleted. This mimics the traditional CASCADE behavior of a SQL DELETE.
When the soft-delete is performed, the system makes a ChangeSet object which tracks all affected objects of this delete request. Later, when an undelete is requested, this ChangeSet is referenced to do a cascading undelete.
If you are undeleting an object that was part of a ChangeSet, that entire ChangeSet is undeleted.
Once undeleted, the ChangeSet object is removed from the underlying database with a regular ("hard") delete.
When using cascade delete, the default behaviour when the call to delete a related object raises an exception is
to fallback to deleting all the entities for that model class from the database. You can prevent this behaviour
by using the SOFTDELETE_CASCADE_ALLOW_DELETE_ALL
setting. Set this to False
to prevent the behaviour.
Can be tested directly with the following command:
django-admin.py test softdelete --settings="softdelete.settings"