Django admin makes the field read-only when obj changes, but is required when adding a new obj

In admin, I would like to disable the field when modifying an object, but make it necessary when adding a new object.

What is the django way to do this?

+78
django django-admin
Dec 03 '10 at 8:02
source share
6 answers

You can override the admin method get_readonly_fields :

 class MyModelAdmin(admin.ModelAdmin): def get_readonly_fields(self, request, obj=None): if obj: # editing an existing object return self.readonly_fields + ('field1', 'field2') return self.readonly_fields 
+153
Dec 03 '10 at 14:24
source share

If you want to set all read- only fields in the change window only, override admin get_readonly_fields:

 def get_readonly_fields(self, request, obj=None): if obj: # editing an existing object # All model fields as read_only return self.readonly_fields + tuple([item.name for item in obj._meta.fields]) return self.readonly_fields 

And , if you want to hide the save buttons in view mode :

  • Change the view

     def change_view(self, request, object_id, form_url='', extra_context=None): ''' customize edit form ''' extra_context = extra_context or {} extra_context['show_save_and_continue'] = False extra_context['show_save'] = False extra_context['show_save_and_add_another'] = False # this not works if has_add_permision is True return super(TransferAdmin, self).change_view(request, object_id, extra_context=extra_context) 
  • Change permissions if the user is trying to change:

     def has_add_permission(self, request, obj=None): # Not too much elegant but works to hide show_save_and_add_another button if '/change/' in str(request): return False return True 

    This solution was tested with Django 1.11

+10
Apr 28 '17 at 12:19
source share

FYI: in case someone encounters the same two problems that I encountered:

  • You still need to declare any readonly_fields in the body of the class as the readonly_fields class attribute will be accessible from verification (see django.contrib.admin.validation: validate_base (), line.213 appx)

  • This will not work with Inlines since the obj passed to get_readonly_fields () is the parent obj (I have two pretty hacker and low level solutions using css or js)

+3
Apr 15 '11 at 11:33
source share

An option based on Bernhard Vallant's previous excellent suggestion, which also retains any possible customization provided by the base class (if any):

 class MyModelAdmin(BaseModelAdmin): def get_readonly_fields(self, request, obj=None): readonly_fields = super(MyModelAdmin, self).get_readonly_fields(request, obj) if obj: # editing an existing object return readonly_fields + ['field1', ..] return readonly_fields 
+2
Oct 21 '17 at 16:21
source share

You can do this by overriding the formfield_for_foreignkey ModelAdmin method:

 from django import forms from django.contrib import admin from yourproject.yourapp.models import YourModel class YourModelAdmin(admin.ModelAdmin): class Meta: model = YourModel def formfield_for_foreignkey(self, db_field, request=None, **kwargs): # Name of your field here if db_field.name == 'add_only': if request: add_opts = (self._meta.app_label, self._meta.module_name) add = u'/admin/%s/%s/add/' % add_opts if request.META['PATH_INFO'] == add: field = db_field.formfield(**kwargs) else: kwargs['widget'] = forms.HiddenInput() field = db_field.formfield(**kwargs) return field return admin.ModelAdmin(self, db_field, request, **kwargs) 
0
Dec 03 '10 at 11:19
source share

Received a similar problem. I solved it using "add_fieldsets" and "limited_fieldsets" in ModelAdmin.

 from django.contrib import admin class MyAdmin(admin.ModelAdmin): declared_fieldsets = None restricted_fieldsets = ( (None, {'fields': ('mod_obj1', 'mod_obj2')}), ( 'Text', {'fields': ('mod_obj3', 'mod_obj4',)}), ) add_fieldsets = ( (None, { 'classes': ('wide',), 'fields': ('add_obj1', 'add_obj2', )}), ) 

See for example: http://code.djangoproject.com/svn/django/trunk/django/contrib/auth/admin.py

But this will not protect your model from later changes to add_objX. If you want this too, I think you need to go through the Save class and check the changes there.

See: www.djangoproject.com/documentation/models/save_delete_hooks/

Griz, Nick

0
Dec 03 '10 at 11:32
source share



All Articles