Skip to content

Instantly share code, notes, and snippets.

@aaugustin
Last active August 7, 2022 19:39
Show Gist options
  • Star 37 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save aaugustin/1388243 to your computer and use it in GitHub Desktop.
Save aaugustin/1388243 to your computer and use it in GitHub Desktop.
Read-only ModelAdmin for Django
from django.contrib import admin
class ReadOnlyModelAdmin(admin.ModelAdmin):
"""
ModelAdmin class that prevents modifications through the admin.
The changelist and the detail view work, but a 403 is returned
if one actually tries to edit an object.
Source: https://gist.github.com/aaugustin/1388243
"""
actions = None
# We cannot call super().get_fields(request, obj) because that method calls
# get_readonly_fields(request, obj), causing infinite recursion. Ditto for
# super().get_form(request, obj). So we assume the default ModelForm.
def get_readonly_fields(self, request, obj=None):
return self.fields or [f.name for f in self.model._meta.fields]
def has_add_permission(self, request):
return False
# Allow viewing objects but not actually changing them.
def has_change_permission(self, request, obj=None):
return (request.method in ['GET', 'HEAD'] and
super().has_change_permission(request, obj))
def has_delete_permission(self, request, obj=None):
return False
@mayela
Copy link

mayela commented Dec 1, 2016

Have you ever tried doing a model readonly conditionally?
Example:
def has_delete_permission(self, request, obj): if obj.status == 'done': return False return True

@daltonpinheiro
Copy link

how to applicate the code of line 19 to 31 only when is superuser?

@daltonpinheiro
Copy link

sorry, how to applicate the code of line 19 to 31 only when is not superuser?

@morrah
Copy link

morrah commented Aug 31, 2018

@daltonpinheiro request object is passed as an argument, so you can check who performes the action:

def has_add_permission(self, request):
    if not request.user.is_superuser:
        return False
    return True

@LECbg
Copy link

LECbg commented Jan 22, 2021

I'm using Django 2.2.10 and it actually works just like this:

class ReadOnlyModelAdmin(admin.ModelAdmin):

    def has_add_permission(self, request):
        return False

    def has_change_permission(self, request, obj=None):
        return False

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

The change URL redirects to the view one (no need to make every field read-only) and ModelAdmin's _filter_actions_by_permissions removes every action.

@aaugustin
Copy link
Author

Yes, this gist no longer serves a purpose since the Django admin gained a "view" permission. Back then it didn't exist!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment