Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Whole model as read-only

Is there a way to make a model read-only in the django admin? but I mean the whole model. So, no adding, no deleting, no changing, just see the objects and the fields, everything as read-only?

like image 693
juliomalegria Avatar asked Oct 27 '11 18:10

juliomalegria


2 Answers

ModelAdmin provides the hook get_readonly_fields() - the following is untested, my idea being to determine all fields the way ModelAdmin does it, without running into a recursion with the readonly fields themselves:

from django.contrib.admin.util import flatten_fieldsets

class ReadOnlyAdmin(ModelAdmin):
    def get_readonly_fields(self, request, obj=None):
        if self.declared_fieldsets:
            fields = flatten_fieldsets(self.declared_fieldsets)
        else:
            form = self.get_formset(request, obj).form
            fields = form.base_fields.keys()
        return fields

then subclass/mixin this admin whereever it should be a read-only admin.

For add/delete, and to make their buttons disappear, you'll probably also want to add

    def has_add_permission(self, request):
        # Nobody is allowed to add
        return False
    def has_delete_permission(self, request, obj=None):
        # Nobody is allowed to delete
        return False

P.S.: In ModelAdmin, if has_change_permission (lookup or your override) returns False, you don't get to the change view of an object - and the link to it won't even be shown. It would actually be cool if it did, and the default get_readonly_fields() checked the change permission and set all fields to readonly in that case, like above. That way non-changers could at least browse the data... given that the current admin structure assumes view=edit, as jathanism points out, this would probably require the introduction of a "view" permission on top of add/change/delete...

EDIT: regarding setting all fields readonly, also untested but looking promising:

readonly_fields = MyModel._meta.get_all_field_names()

EDIT: Here's another one

if self.declared_fieldsets:
    return flatten_fieldsets(self.declared_fieldsets)
else:
    return list(set(
        [field.name for field in self.opts.local_fields] +
        [field.name for field in self.opts.local_many_to_many]
    ))
like image 126
Danny W. Adair Avatar answered Sep 24 '22 01:09

Danny W. Adair


As "view permissions" will not make it into Django 1.11, unfortunately, here's a solution that makes your ModelAdmin read-only by making both saving model changes and adding model history log entries a no-op.

def false(*args, **kwargs):
    """A simple no-op function to make our changes below readable."""
    return False

class MyModelReadOnlyAdmin(admin.ModelAdmin):
    list_display = [
        # list your admin listview entries here (as usual) 
    ]
    readonly_fields = [
        # list your read-only fields here (as usual)
    ]

    actions = None
    has_add_permission = false
    has_delete_permission = false
    log_change = false
    message_user = false
    save_model = false

(NOTE: Don't mistake the false no-op helper with the False builtin. If you don't sympathize with the helper function outside the class move it into the class, call it no_op or something else, or override the affected attributes by usual defs. Less DRY, but if you don't care...)

This will:

  1. remove the actions drop-down box (with "delete") in the list view
  2. disallow adding new model entries
  3. disallow deleting existing model entries
  4. avoid creating log entries in the model history
  5. avoid displaying "was changed successfully" messages after saving
  6. avoid saving changeform changes to the database

It will not:

  • remove or replace the two buttons "Save and continue editing" and "SAVE" (which would be nice to improve the user experience)

Note that get_all_field_names (as mentioned in the accepted answer) was removed in Django 1.10. Tested with Django 1.10.5.

like image 26
Peterino Avatar answered Sep 24 '22 01:09

Peterino