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.
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))
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
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)
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.