Readonly admin fields

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
from django import forms

class ReadOnlyWidget(forms.Widget):
    def __init__(self, original_value, display_value):
        self.original_value = original_value
        self.display_value = display_value

        super(ReadOnlyWidget, self).__init__()

    def render(self, name, value, attrs=None):
        if self.display_value is not None:
            return unicode(self.display_value)
        return unicode(self.original_value)

    def value_from_datadict(self, data, files, name):
        return self.original_value

class ReadOnlyAdminFields(object):
    def get_form(self, request, obj=None):
        form = super(ReadOnlyAdminFields, self).get_form(request, obj)

        if hasattr(self, 'readonly'):
            for field_name in self.readonly:
                if field_name in form.base_fields:

                    if hasattr(obj, 'get_%s_display' % field_name):
                        display_value = getattr(obj, 'get_%s_display' % field_name)()
                    else:
                        display_value = None

                    form.base_fields[field_name].widget = ReadOnlyWidget(getattr(obj, field_name, ''), display_value)
                    form.base_fields[field_name].required = False

        return form

Comments

mredar (on August 26, 2008):

This worked great. Should be part of the main Django branch IMHO, seems to be a bit of functionality that is needed quite often!

#

djbe (on August 27, 2008):

It works - but when I try to update existing data via admin interface, I get blocked and receive the errormessage:

"Enter a list of values."

This happens on a DateTime field. I have not tried others so far.

#

ekellner (on August 28, 2008):

I think this needs to output a hidden input field on render, or else the form that this belongs to will not validate. I think just by inheriting from widget.HiddenInput and calling super on render, it should (basically) work.

#

ekellner (on August 28, 2008):

I see, it doesn't use a hidden field because it intercepts the value_from_datadict call to the widget. Unfortunately, when the field owning the widget expects a form value isn't the same as the object property value -- as is the case for widgets that post more than 1 value, or foreign key values where the field expects an id -- the widget doesn't provide the value in the right format for the field.

#

rickvanderzwet (on November 30, 2008):

Will there be some way to also enable this very useful fields in InlineForms as well? As snippet below, does not seems to fix it.

# typical admin.py file:
from django.contrib import admin
from foo.bar import ReadOnlyAdminFields

class MyModelInline(ReadOnlyAdminFields, admin.TabularInline):
    readonly = ('fieldFoo', 'fieldBar',)

class MyModelAdmin(ReadOnlyAdminFields,admin.ModelAdmin):
    readonly = ('field1', 'field2',)
    inlines = (MyModelInline, )

#

(Forgotten your password?)

You may use Markdown syntax here, but raw HTML will be removed.