How to delete records in Django

Video thumbnail

In any CRUD system, the deleting or elimination operation (in English, "delete") allows for deleting a record or a set of them from the database; this is one of the simplest operations to perform but also the riskiest, since it's an operation that cannot be reversed; once the record is deleted, there's no turning back and the record cannot be recovered. Therefore, it's usually an operation that is limited, either by privileges or by adding warning dialogs, among other types of solutions. For now, what interests us is performing the operation and that's it, without worrying about implementing additional logic to prevent this type of operation.

Deleting records in Django is one of the simplest operations of any CRUD, but also one of the riskiest. Once data is deleted, there's no going back: the record disappears from the database and cannot be easily recovered.

That's why, even though it's technically one line of code, it's good to understand well what happens behind the scenes, when to use each method, and how to avoid accidentally deleting something. In my case, I usually limit this action to users with specific permissions and always display a confirmation dialog before deletion.

As part of our CRUD, we have the deletion phase, which consists of two fundamental steps:

  1. Get a reference to the element we want to delete using the ORM.
  2. Delete it.

Deleting a record with the delete() method

The most direct way to delete a record in Django is by using the .delete() method of the ORM. The usual practice is to do it from a function-based view.

Getting the object to delete with get_object_or_404

Before deleting, we first need to retrieve the record:

def delete(request, pk):
   product = get_object_or_404(Product, id=pk)
   product.delete()
   return redirect('gestion:index')

Redirections in Django were explained in the previous article; otherwise, once deleted, you can generally do a couple of things. Here, we do a redirection, but if, for example, this function is consumed via JavaScript, you can return a JSON with a response to be analyzed:

from django.http import JsonResponse
def delete(request, pk):
    product = get_object_or_404(Product, id=pk)
    product.delete()
    return JsonResponse({'status': 'success', 'message': 'Producto eliminado'})

In the previous example, if the product does not exist, Django returns a 404 error. If it does exist, it deletes it and redirects to the main view.

Finally, the reference to the previous function:

<a href="{% url 'gestion:delete' p.id %}">Delete</a>

Deleting multiple records with QuerySet.delete()

Sometimes you need to delete more than one record at a time. Django allows this directly on a QuerySet:

Product.objects.filter(is_active=False).delete()

This method deletes all objects that meet the given condition. It's very useful for periodic cleanups or automatic tasks.

Tip: use precise filters. In a previous project, a poorly written filter deleted more than expected. Since then, I always check with .count() first:

qs = Product.objects.filter(is_active=False)
print(qs.count())  # Confirm quantity before deleting
qs.delete()

Soft delete: deleting without removing from the database

There are cases where we don't want to lose the information, just "hide" it. This is where soft delete comes in: instead of physically deleting the record, we mark a field (for example, `is_active=False`).

What it is and when to use it

It is used when the data might be needed later (history, audits, etc.). It's common in applications where historical integrity matters, such as billing systems or CRMs.

Implementation with the `is_active` field

class Product(models.Model):
   name = models.CharField(max_length=200)
   is_active = models.BooleanField(default=True)
   def delete(self, *args, **kwargs):
       self.is_active = False
       self.save()

With this, every time you call `product.delete()`, instead of deleting the record, it will only mark it as inactive.

Advantages and Limitations
Advantages    Limitations
Data history is preserved    The database grows faster
Allows record recovery    Requires filtering `is_active=True` in all queries
Prevents irreversible errors    Does not free up physical space in the database

Best practices and security when deleting data

Deleting data might seem trivial, but it must be done thoughtfully.

In my experience, these are the practices that help the most:

Confirmations and user permissions

Before deleting something, ask the user if they really want to do it. In Django, you can use a modal or an intermediate confirmation template.
Also check permissions:

if not request.user.has_perm('app.delete_product'):
   return JsonResponse({'error': 'No autorizado'}, status=403)

Common errors and how to avoid them

  • Not using `get_object_or_404`: can cause non-existent object errors.
  • Not confirming filters in bulk deletions.
  • Not handling redirection or response after deleting.

A small oversight can leave a half-empty database... and nobody wants that.

Complete Example: CRUD with deletion in Django

A typical example of a complete flow includes:

  • Link in template
  • `delete()` view
  • Redirection or JSON response

Template:

<a href="{% url 'gestion:delete' p.id %}" onclick="return confirm('¿Seguro que deseas borrar este producto?');">
 Delete
</a>

View:

def delete(request, pk):
   product = get_object_or_404(Product, id=pk)
   product.delete()
   return redirect('gestion:index')

If you prefer to do it without reloading the page, you can use the Fetch API to send the DELETE request and update the table dynamically.

Conclusion

Deleting records in Django is easy, but doing it well requires practice and caution.
In my case, I learned that it's always worth confirming the action and, when the information is valuable, opting for a soft delete.

In summary:

  • Use .delete() to truly delete.
  • Use soft delete to preserve data.
  • Use permissions and confirmations to avoid disasters.
  • With that, your CRUD will be secure, clean, and professional.

Frequently Asked Questions (FAQ)

How do I delete a specific record in Django?
With .delete() on the object obtained by get_object_or_404.

What's the difference between delete() and QuerySet.delete()?
The first one deletes a specific instance; the second one can delete multiple records at once.

What is a "soft delete"?
A logical deletion: the record is marked as inactive but remains in the database.

Can I recover a deleted record?
Only if you use soft delete or have a database backup.

How can I prevent users without permissions from deleting records?
Control permissions with `user.has_perm('app.delete_model')` and authenticate the views.

The next step is to learn how to use forms in Django

Learn how to delete records in Django, including possible issues, validations, best practices, the soft delete mechanism to avoid accidentally deleting records, deleting multiple records, and more.

I agree to receive announcements of interest about this Blog.

Andrés Cruz

ES En español