How to disable delete option in Django admin?

How to disable delete option in Django admin?

The TL;DR answer:

You need to add a new method has_delete_permission in the Admin class where you want to disable the delete function.

from django.contrib import admin

class OrganisationAdmin(admin.ModelAdmin):
    list_display = ("name", "id", "is_active", "domain_name")
    
    def has_delete_permission(self, request, obj=None):
        # Disable delete
        return False

The Detailed Answer:

For disabling delete option in Django admin, the first thing we need to check how does Django admin work. If you open the ModelAdmin class code you would be able to see the has_delete_permission getting called on to see if the user who is making the request has permission to delete or not.

django/django
The Web framework for perfectionists with deadlines. - django/django
class BaseModelAdmin(metaclass=forms.MediaDefiningClass):
    """Functionality common to both ModelAdmin and InlineAdmin."""
    .....
    .....
    
    def has_delete_permission(self, request, obj=None):
        """
        Return True if the given request has permission to change the 	given
        Django model instance, the default implementation doesn't examine the
        `obj` parameter.
        Can be overridden by the user in subclasses. In such case it should
        return True if the given request has permission to delete the `obj`
        model instance. If `obj` is None, this should return True if the given
        request has permission to delete *any* object of the given type.
        """
        opts = self.opts
        codename = get_permission_codename('delete', opts)
        return request.user.has_perm("%s.%s" % (opts.app_label, codename))
original django admin code

Whenever a Django admin user would be making the request we check if the user has permission to make delete operation. Now We want to disable the delete operation for all users so, the best way is to return False for any request when made.

If you override this method then automatically the all Django admin user request would start calling it. I would always recommend to turning the delete feature from admin, why so? Because I have seen way too many times people deleting production data accidentally when they have the feature this easy.

Now the question comes, what would be a better way to disable delete feature throughout all admins. You can manually add the method and disable but this is not scalable since you never know when the developer would forget to add the method. So now the question comes how to solve it in a better way?

In my experience always write a wrapper over such systems so that you have better control. Like tomorrow you want a particular user to give delete access then you cannot manually go to all places and change the code. Here comes the inheritance concept

from django.contrib import admin


class BaseAdmin(admin.ModelAdmin):
    readonly_fields = ("created_at", "updated_at")

    def has_delete_permission(self, request, obj=None):
        # Disable delete
        return False

common/custom_admin.py

The above custom admin should be used throughout the project.

from common import custom_admin
from django.contrib import admin

from blog import models 

class AuthorAdmin(custom_admin.BaseAdmin):
    list_display = ("name", "id", "is_active")


class TagAdmin(custom_admin.BaseAdmin):
    list_display = ("name", "id", "created_at")

admin.site.register(models.Author, AuthorAdmin)
admin.site.register(models.Tag, TagAdmin)
blog/admin.py

Now automatically any admin using the BaseAdmin would have delete feature disabled. Tomorrow someone wants to enable the delete functionality for a particular user, then they need to update just one place.