Readonly models in Django admin interface?
The admin is for editing, not just viewing (you won't find a "view" permission). In order to achieve what you want you'll have to forbid adding, deleting, and make all fields readonly:
class MyAdmin(ModelAdmin): def has_add_permission(self, request, obj=None): return False def has_delete_permission(self, request, obj=None): return False
(if you forbid changing you won't even get to see the objects)
For some untested code that tries to automate setting all fields read-only see my answer to Whole model as read-only
EDIT: also untested but just had a look at my LogEntryAdmin and it has
readonly_fields = MyModel._meta.get_all_field_names()
Don't know if that will work in all cases.
EDIT: QuerySet.delete() may still bulk delete objects. To get around this, provide your own "objects" manager and corresponding QuerySet subclass which doesn't delete - see Overriding QuerySet.delete() in Django
Here are two classes I am using to make a model and/or it's inlines read only.
For model admin:
from django.contrib import adminclass ReadOnlyAdmin(admin.ModelAdmin): readonly_fields = [] def get_readonly_fields(self, request, obj=None): return list(self.readonly_fields) + \ [field.name for field in obj._meta.fields] + \ [field.name for field in obj._meta.many_to_many] def has_add_permission(self, request): return False def has_delete_permission(self, request, obj=None): return Falseclass MyModelAdmin(ReadOnlyAdmin): pass
For inlines:
class ReadOnlyTabularInline(admin.TabularInline): extra = 0 can_delete = False editable_fields = [] readonly_fields = [] exclude = [] def get_readonly_fields(self, request, obj=None): return list(self.readonly_fields) + \ [field.name for field in self.model._meta.fields if field.name not in self.editable_fields and field.name not in self.exclude] def has_add_permission(self, request): return Falseclass MyInline(ReadOnlyTabularInline): pass
See https://djangosnippets.org/snippets/10539/
class ReadOnlyAdminMixin(object): """Disables all editing capabilities.""" change_form_template = "admin/view.html" def __init__(self, *args, **kwargs): super(ReadOnlyAdminMixin, self).__init__(*args, **kwargs) self.readonly_fields = [f.name for f in self.model._meta.get_fields()] def get_actions(self, request): actions = super(ReadOnlyAdminMixin, self).get_actions(request) del_action = "delete_selected" if del_action in actions: del actions[del_action] return actions def has_add_permission(self, request): return False def has_delete_permission(self, request, obj=None): return False def save_model(self, request, obj, form, change): pass def delete_model(self, request, obj): pass def save_related(self, request, form, formsets, change): pass
templates/admin/view.html
{% extends "admin/change_form.html" %}{% load i18n %}{% block submit_buttons_bottom %} <div class="submit-row"> <a href="../">{% blocktrans %}Back to list{% endblocktrans %}</a> </div>{% endblock %}
templates/admin/view.html (for Grappelli)
{% extends "admin/change_form.html" %}{% load i18n %}{% block submit_buttons_bottom %} <footer class="grp-module grp-submit-row grp-fixed-footer"> <header style="display:none"><h1>{% trans "submit options"|capfirst context "heading" %}</h1></header> <ul> <li><a href="../" class="grp-button grp-default">{% blocktrans %}Back to list{% endblocktrans %}</a></li> </ul> </footer>{% endblock %}