Package: django-deletion-records
Django Deletion RecordsThis simple Django app contains a mechanism to track deleted model records.
Unlike the soft-deletion mechanism, the deleted content is saved to a separate
table.The deleted records are inserted via database triggers, so you don't have to
write any additional code or change your base model classes. In fact, you only
need to perform related migration operations, and you are good to go; the
deleted records will start to appear in Django admin site.Comparison with soft deleteProsNo overly-complicated application code. To make soft-deletion work, you
need to override model managers so that deleted records are kept out. Even
then, the abstraction is very leaky when managers are not available such
as doing aggregations or joins.Database constraints are easier since you don't need to consider deleted
records.Managing relationships are easier, for example you don't need to worry
aboutForeignKeycascades.Deleted records do not affect undeleted records at all. More often than
not, soft-delete create problems with new or existing rows because
someone forgets that soft-deleted records are actually there.ConsReversing deletions are pretty difficult. In soft-delete, you can just flip
a column (most of the time). For deletion records, you'll have to manually
re-insert the data (and its dependencies).Data lookup is relatively difficult especially if you're maintaining
complex relationships spanning multiple tables. In soft-delete, you can
just do regular SQL lookups. However, deletion records require custom
resolution forForeignKey's and such.Deletion operations arerelativelyslower since soft-delete updates
are faster and there is no trigger penalty.Soft-deleting is convenient when you need to restore data but creates
complexity in application code. Deletion records are much easier manage,
however it is difficult to restore data.You may also use soft-deletes alongside deletion records if you want to keep
some tables soft-deleted and others recorded (for example, as audit logs).Installationdjango-deletion-recordsonly works for PostgreSQL, other database backends
are not supported.Install from PyPI:pipinstalldjango-deletion-recordsAdddeletion_recordsto yourINSTALLED_APPS, such as:INSTALLED_APPS=['django.contrib.admin','django.contrib.auth','django.contrib.contenttypes','django.contrib.sessions','django.contrib.messages','django.contrib.staticfiles',# ...'deletion_records',]Run migrate fordeletion_records:pythonmanage.pymigratedeletion_records

Operationstoperform:Applyallmigrations:deletion_records
Runningmigrations:Applyingdeletion_records.0001_initial...OKMarking a model for deletionTo start recording deletions for a given model, you'll need to perform aRunSQLoperation (that will create the related trigger) via Django
migrations.To start, create an empty migration file in your related app:pythonmanage.pymakemigrations--emptyyour-appThis will create an empty migration with no operations. To get the related
operations we'll use thedeletion_migration_operationsmanagement command:pythonmanage.pydeletion_migration_operationsyourapp.User# yourapp.Useroperations=[migrations.RunSQL("""CREATE TRIGGER deleted_record_insertAFTER DELETEON yourapp_userFOR EACH ROWEXECUTE FUNCTION deletion_record_insert();""",reverse_sql="DROP TRIGGER IF EXISTS deleted_record_insert ON yourapp_user CASCADE;",)]Copy the given operations to your empty migration file, and apply the
migrations. Deletion records will start to appear, that's it!TipsYou can supply multiple models fordeletion_migration_operationsto get
multiple operations at once.You can have multiple operations in one migration file if you want to. It
just depends on how you want to handle the migrations.If you want to enable deletion records for a third party model, you can
still employ the steps above. You just need to figure out a proper
application (that'll hold the migrations), people generally use "core" apps
to do that kind of stuff.Reversing the migration created above will drop the related trigger, thus
stopping the deletion recording. The formerly deleted records will be still
available.If you want to hard-delete some records (or manage deleted records for any
other reason), you can use the provided model as such:fromdeletion_records.modelsimportDeletedRecord# Deletes User objects with provided ids.DeletedRecord.objects.filter(table_name="yourapp_user",object_id__in=[2,3,4]).delete()fromdeletion_records.modelsimportDeletedRecord# Fetch a deleted record and view the data.user=DeletedRecord.objects.get(table_name="account_user",object_id=276833)assertuser.data=={"id":276833,"email":"lauren62@example.com","is_staff":False,"password":"pbkdf2_sha256$600000$4X48PbRIeemb2ECW1pIlO4$jFuePmugUuTE4D6nIbP9TxGKcYxLBut81bR4JbshU8I=","username":"qwSyeamDqT","is_active":True,"last_name":"Jackson","first_name":"Cynthia","last_login":None,"date_joined":"2024-01-16T19:35:32.331011+00:00","is_superuser":False,}You can also browse deleted records via Django admin.CreditsI primarily read the following posts to implement this in Django:https://brandur.org/fragments/deleted-record-inserthttps://brandur.org/soft-deletion