137

Even though a field is marked as 'editable=False' in the model, I would like the admin page to display it. Currently, it hides the field altogether.. How can this be achieved?

Super Kai - Kazuya Ito
  • 22,221
  • 10
  • 124
  • 129
GabiMe
  • 18,105
  • 28
  • 76
  • 113

7 Answers7

253

Use Readonly Fields. Like so (for django >= 1.2):

class MyModelAdmin(admin.ModelAdmin):
    readonly_fields=('first',)
mlissner
  • 17,359
  • 18
  • 106
  • 169
tback
  • 11,138
  • 7
  • 47
  • 71
  • 9
    +1. Especially if you _don't_ plan to edit the field at all in Admin. – Manoj Govindan Oct 19 '10 at 16:05
  • 4
    This does not work here (Django 2.0). The field is not displayed then in the admin interface. – nerdoc Sep 05 '18 at 12:47
  • 1
    I just created a sample application to reproduce your error (django 2.0.8, python 3.5). This still works fine. Maybe something else is wrong in your app @nerdoc? – tback Sep 05 '18 at 13:29
  • oOops. Typical fast-shot. Did not test, seems to be a problem with my installation. Thanks, and sorry. – nerdoc Sep 06 '18 at 15:35
  • 4
    For me admin crashed when I added it to `fields`, but when I added it to `readonly_fields` it didn't show up until I added it to both and then it appeared in admin. – owenfi Sep 17 '18 at 06:04
  • To confirm @nerdoc make sure you add 'MyModelAdmin' to the admin.site.register(...) it should work. If it doesn't you have other issues. – Jody Fitzpatrick Jan 15 '19 at 01:35
19

Update

This solution is useful if you want to keep the field editable in Admin but non-editable everywhere else. If you want to keep the field non-editable throughout then @Till Backhaus' answer is the better option.

Original Answer

One way to do this would be to use a custom ModelForm in admin. This form can override the required field to make it editable. Thereby you retain editable=False everywhere else but Admin. For e.g. (tested with Django 1.2.3)

# models.py
class FooModel(models.Model):
    first = models.CharField(max_length = 255, editable = False)
    second  = models.CharField(max_length = 255)

    def __unicode__(self):
        return "{0} {1}".format(self.first, self.second)

# admin.py
class CustomFooForm(forms.ModelForm):
    first = forms.CharField()

    class Meta:
        model = FooModel
        fields = ('second',)

class FooAdmin(admin.ModelAdmin):
    form = CustomFooForm

admin.site.register(FooModel, FooAdmin)
Community
  • 1
  • 1
Manoj Govindan
  • 72,339
  • 21
  • 134
  • 141
  • 2
    This does not work, at least on django 1.6 The form is displayed correctly in the admin panel, but when I save a form and return to it again, the forms value is default again. – Euphorbium Oct 07 '14 at 12:42
14

Add the fields you want to display on your admin page.
Then add the fields you want to be read-only.
Your read-only fields must be in fields as well.

class MyModelAdmin(admin.ModelAdmin):
    fields = ['title', 'author', 'published_date', 'updated_date', 'created_date']
    readonly_fields = ('updated_date', 'created_date')
gabriel
  • 411
  • 5
  • 8
  • 1
    Thanks, this solved the issue for me. I simply put the `readonly_fields` on top and let `fields` be the editable fields `+ readonly_fields` (both are tuples in my code; I don't see why one would declare them as lists). – theberzi Oct 20 '20 at 13:14
4

You could also set the readonly fields as editable=False in the model (django doc reference for editable here). And then in the Admin overriding the get_readonly_fields method.

# models.py
class MyModel(models.Model):
  first = models.CharField(max_length=255, editable=False)

# admin.py
class MyModelAdmin(admin.ModelAdmin):
  def get_readonly_fields(self, request, obj=None):
    return [f.name for f in obj._meta.fields if not f.editable]
raphodn
  • 196
  • 1
  • 6
1

With the above solution I was able to display hidden fields for several objects but got an exception when trying to add a new object.

So I enhanced it like follows:

class HiddenFieldsAdmin(admin.ModelAdmin):
def get_readonly_fields(self, request, obj=None):
    try:
        return [f.name for f in obj._meta.fields if not f.editable]
    except:
        # if a new object is to be created the try clause will fail due to missing _meta.fields
        return ""

And in the corresponding admin.py file I just had to import the new class and add it whenever registering a new model class

from django.contrib import admin
from .models import Example, HiddenFieldsAdmin

admin.site.register(Example, HiddenFieldsAdmin)

Now I can use it on every class with non-editable fields and so far I saw no unwanted side effects.

Schnurcks
  • 21
  • 5
0

You can try this

@admin.register(AgentLinks)
class AgentLinksAdmin(admin.ModelAdmin):
    readonly_fields = ('link', )
Bercove
  • 987
  • 10
  • 18
0

You can display editable=False fields with readonly_fields as shown below:

@admin.register(MyModel)
class MyModelAdmin(admin.ModelAdmin):
    readonly_fields = ('updated_date', 'created_date')

And, if assigning editable=False fields to fields, you also need to assign them to readonly_fields as shown below:

@admin.register(MyModel)
class MyModelAdmin(admin.ModelAdmin):
    fields = ('updated_date', 'created_date')
    readonly_fields = ('updated_date', 'created_date')

Because, if only assigning editable=False fields to fields without assigning them to readonly_fields as shown below:

@admin.register(MyModel)
class MyModelAdmin(admin.ModelAdmin):
    fields = ('updated_date', 'created_date')
    # readonly_fields = ('updated_date', 'created_date')

Then, the error below occurs:

django.core.exceptions.FieldError: 'updated_date' cannot be specified for MyModel model form as it is a non-editable field. Check fields/fieldsets/exclude attributes of class MyModelAdmin.

Super Kai - Kazuya Ito
  • 22,221
  • 10
  • 124
  • 129