Model

Built-in model

class safedelete.models.SafeDeleteModel(*args, **kwargs)[source]

Abstract safedelete-ready model.

Note

To create your safedelete-ready models, you have to make them inherit from this model.

Attribute deleted:
 

DateTimeField set to the moment the object was deleted. Is set to None if the object has not been deleted.

Attribute deleted_by_cascade:
 

BooleanField set True whenever the object is deleted due cascade operation called by delete method of any parent Model. Default value is False. Later if its parent model calls for cascading undelete, it will restore only child classes that were also deleted by a cascading operation (deleted_by_cascade equals to True), i.e. all objects that were deleted before their parent deletion, should keep deleted if the same parent object is restored by undelete method.

If this behavior isn’t desired, class that inherits from SafeDeleteModel can override this attribute by setting it as None: overriding model class won’t have its deleted_by_cascade field and won’t be restored by cascading undelete even if it was deleted by a cascade operation.

>>> class MyModel(SafeDeleteModel):
...     deleted_by_cascade = None
...     my_field = models.TextField()
Attribute _safedelete_policy:
 

define what happens when you delete an object. It can be one of HARD_DELETE, SOFT_DELETE, SOFT_DELETE_CASCADE, NO_DELETE and HARD_DELETE_NOCASCADE. Defaults to SOFT_DELETE.

>>> class MyModel(SafeDeleteModel):
...     _safedelete_policy = SOFT_DELETE
...     my_field = models.TextField()
...
>>> # Now you have your model (with its ``deleted`` field, and custom manager and delete method)
Attribute objects:
 

The safedelete.managers.SafeDeleteManager returns the non-deleted models.

Attribute all_objects:
 

The safedelete.managers.SafeDeleteAllManager returns all the models (non-deleted and soft-deleted).

Attribute deleted_objects:
 

The safedelete.managers.SafeDeleteDeletedManager returns the soft-deleted models.

save(keep_deleted=False, **kwargs)[source]

Save an object, un-deleting it if it was deleted.

Args:
keep_deleted: Do not undelete the model if soft-deleted. (default: {False}) kwargs: Passed onto save().

Note

Undeletes soft-deleted models by default.

undelete(force_policy=None, **kwargs)[source]

Undelete a soft-deleted model.

Args:
force_policy: Force a specific undelete policy. (default: {None}) kwargs: Passed onto save().

Note

Will raise a AssertionError if the model was not soft-deleted.

classmethod has_unique_fields()[source]

Checks if one of the fields of this model has a unique constraint set (unique=True).

It also checks if the model has sets of field names that, taken together, must be unique.

Args:
model: Model instance to check
class safedelete.models.SafeDeleteMixin(*args, **kwargs)[source]

SafeDeleteModel was previously named SafeDeleteMixin.

Deprecated since version 0.4.0: Use SafeDeleteModel instead.

Policies

You can change the policy of your model by setting its _safedelete_policy attribute. The different policies are:

safedelete.models.HARD_DELETE
This policy will:
  • Hard delete objects from the database if you call the delete() method.

    There is no difference with « normal » models, but you can still manually mask them from the database, for example by using obj.delete(force_policy=SOFT_DELETE).

safedelete.models.SOFT_DELETE

This policy will:

This will make the objects be automatically masked (and not deleted), when you call the delete() method. They will NOT be masked in cascade.

safedelete.models.SOFT_DELETE_CASCADE

This policy will:

This will make the objects be automatically masked (and not deleted) and all related objects, when you call the delete() method. They will be masked in cascade.

safedelete.models.HARD_DELETE_NOCASCADE
This policy will:
  • Delete the object from database if no objects depends on it (e.g. no objects would have been deleted in cascade).
  • Mask the object if it would have deleted other objects with it.
safedelete.models.NO_DELETE
This policy will:
  • Keep the objects from being masked or deleted from your database. The only way of removing objects will be by using raw SQL.

Policies Delete Logic Customization

Each of the policies has an overwritable function in case you need to customize a particular policy delete logic. The function per policy are as follows:

Policy Overwritable Function
SOFT_DELETE soft_delete_policy_action
HARD_DELETE hard_delete_policy_action
HARD_DELETE_NOCASCADE hard_delete_cascade_policy_action
SOFT_DELETE_CASCADE soft_delete_cascade_policy_action

Example:

To add custom logic before or after the execution of the original delete logic of a model with the policy SOFT_DELETE you can overwrite the soft_delete_policy_action function as such:

def soft_delete_policy_action(self, **kwargs):
    # Insert here custom pre delete logic
    delete_response = super().soft_delete_policy_action(**kwargs)
    # Insert here custom post delete logic
    return delete_response

Fields uniqueness

Because unique constraints are set at the database level, set unique=True on a field will also check uniqueness against soft deleted objects. This can lead to confusion as the soft deleted objects are not visible by the user. This can be solved by setting a partial unique constraint that will only check uniqueness on non-deleted objects:

class Post(SafeDeleteModel):
    name = models.CharField(max_length=100)

    class Meta:
        constraints = [
            UniqueConstraint(
                fields=['name'],
                condition=Q(deleted__isnull=True),
                name='unique_active_name'
            ),
        ]