Soft delete sounds simple—until you're the one implementing it in a real-world, regulated application.
In building a financial portfolio management system, we faced the not-so-fun challenge of handling user deletion without compromising data integrity or violating compliance rules. You can't just delete() a user when audit trails, tax records, and GDPR are watching.
So, here's how we designed a clean, maintainable soft delete system using a custom Django User model.
Problem Summary
Most finance or SaaS platforms need to:
- Retain user-related transactions for tax/audit purposes
- Disable login access cleanly
- Restore accidentally deleted accounts
- Avoid cascading deletions of historical data Using Django’s built-in User + separate UserProfile quickly turned into a nightmare: joins everywhere, edge cases all over the place, and no easy path to soft delete.
So we followed Django’s best practice: own your User model from day one.
The Solution (With Code)
Here's a quick breakdown of the implementation:
- ✅ Custom User model based on AbstractUser
- ✅ Added is_deleted, deleted_at, deleted_by
- ✅ Overrode the admin to support soft deletion & restoration
- ✅ Used on_delete=models.PROTECT for critical models like Transaction
- ✅ Queryset filters and indexes for is_deleted
📄 Full walkthrough (with complete code and admin logic):
👉 Read the detailed article
Key Implementation Tips
- is_active=False prevents login
- Soft deletes ≠ just hiding records — handle reversibility and auditing
- Never on_delete=CASCADE sensitive data like financial history
- Use admin actions for bulk delete/restore and badge UI for status
Why This Matters
Soft delete isn’t just for compliance. It protects you from:
- Mistaken deletions
- Breaking historical reporting
- GDPR data logic edge cases
- Limitations of Django’s default User model Plus, migration from default User → custom User later is a huge pain. Better to do it upfront.
💬 Your Turn
Have you implemented soft delete in production? Found better patterns, or do you prefer packages like django-safedelete? Would love to hear your experience or suggestions for scaling this better.
🧵 Or drop thoughts below 👇
Top comments (0)