Readonly models in Django admin interface?

How can I make the model fully read-only in the admin interface? This is for a kind of log table, where I use the administrator functions to search, sort, filter, etc., but there is no need to change the log.

If this seems like a duplicate, here is not what I'm trying to do:

  • I'm not looking for readonly fields (even making each readonly field still allow new entries to be created)
  • I do not want to create a read-only user: each user should be read-only.
+75
django django-admin readonly
Nov 25 2018-11-11T00:
source share
9 answers

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 = self.model._meta.get_all_field_names() def get_actions(self, request): actions = super(ReadOnlyAdminMixin, self).get_actions(request) del actions["delete_selected"] 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 %} 
+17
Nov 05 '15 at 11:50
source share

The administrator is intended for editing, and not just for viewing (you will not find the permission "view"). In order to achieve what you want, you will have to prohibit adding, deleting and making all fields read-only:

 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 change, you will not even see objects)

For some unverified code that tries to automate the installation of all read-only fields, see my answer on the Entire model as read-only

EDIT: also untested, but just looked at my LogEntryAdmin, and it has

 readonly_fields = MyModel._meta.get_all_field_names() 

I don't know if this will work in all cases.

EDIT: QuerySet.delete () can still massively delete objects. To get around this, provide your own โ€œobjectsโ€ manager and a corresponding subclass of QuerySet that does not delete - see Overriding QuerySet.delete () in Django

+66
Nov 25 '11 at 7:14
source share

Here are two classes that I use to make a model and / or it is read-only inline.

For model administrator:

 from django.contrib import admin class 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 False class MyModelAdmin(ReadOnlyAdmin): pass 

For strings:

 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 False class MyInline(ReadOnlyTabularInline): pass 
+43
Nov 09
source share

If you want the user to realize that he / she cannot edit it, the first solution is missing 2 parts. You have deleted the delete action!

 class MyAdmin(ModelAdmin) def has_add_permission(self, request, obj=None): return False def has_delete_permission(self, request, obj=None): return False def get_actions(self, request): actions = super(MyAdmin, self).get_actions(request) if 'delete_selected' in actions: del actions['delete_selected'] return actions 

Second: readonly-based solution works fine on simple models. But it does NOT work if you have an inherited model with foreign keys. Unfortunately, I do not know a solution for this yet. Good try:

The whole model is read-only

But this also does not work for me.

One final note, if you want to think of a broad solution, you must ensure that each line is also read-only.

+12
Nov 03 '12 at 12:10
source share

In fact, you can try this simple solution:

 class ReadOnlyModelAdmin(admin.ModelAdmin): actions = None list_display_links = None # more stuff here def has_add_permission(self, request): return False 
  • actions = None : avoids displaying a drop-down list with the option "Delete selected ..."
  • list_display_links = None : avoids clicking in columns to edit this object
  • has_add_permission() return False allows you to create new objects for this model
+9
Feb 25 '16 at 16:28
source share

If the accepted answer does not work for you, try the following:

 def get_readonly_fields(self, request, obj=None): readonly_fields = [] for field in self.model._meta.fields: readonly_fields.append(field.name) return readonly_fields 
+5
May 8 '13 at 8:45
source share

Compiling @darklow and @josir with great answers, plus adding a bit more to remove the Save and Save and Continue buttons, results in (in Python 3 syntax):

 class ReadOnlyAdmin(admin.ModelAdmin): """Provides a read-only view of a model in Django admin.""" readonly_fields = [] def change_view(self, request, object_id, extra_context=None): """ customize add/edit form to remove save / save and continue """ extra_context = extra_context or {} extra_context['show_save_and_continue'] = False extra_context['show_save'] = False return super().change_view(request, object_id, extra_context=extra_context) def get_actions(self, request): actions = super().get_actions(request) if 'delete_selected' in actions: del actions['delete_selected'] return actions 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 False 

and then you use both

 class MyModelAdmin(ReadOnlyAdmin): pass 

I just tried this with Django 1.11 / Python 3.

+4
May 17 '17 at 15:41
source share

The accepted answer should work, but it will also preserve the readonly order of the fields. You also do not need to hard code the model with this solution.

 class ReadonlyAdmin(admin.ModelAdmin): def __init__(self, model, admin_site): super(ReadonlyAdmin, self).__init__(model, admin_site) self.readonly_fields = [field.name for field in filter(lambda f: not f.auto_created, model._meta.fields)] def has_delete_permission(self, request, obj=None): return False def has_add_permission(self, request, obj=None): return False 
+2
Jan 16 '14 at 2:44
source share

I came across the same requirement when it was necessary to make all read-only fields for certain users in django admin, which led to the use of the django module "django-admin-view-permission" without folding my own code. If you need a finer-grained control to explicitly define fields, then you will need to expand the module. You can check the plugin in action here

+1
Dec 20 '16 at 4:45
source share



All Articles