Django admin: exclude field only in change form

If there is a way to determine if information in the model is being added or changed.

If possible, use this information to exclude fields.

Some pseudo codes to illustrate what I'm talking about.

class SubSectionAdmin(admin.ModelAdmin): if something.change_or_add = 'change': exclude = ('field',) ... 

thanks

+4
django-admin
source share
4 answers
 class SubSectionAdmin(admin.ModelAdmin): # ... def change_view(self, request, object_id, extra_context=None): self.exclude = ('field', ) return super(SubSectionAdmin, self).change_view(request, object_id, extra_context) 
+5
source share

the orwellian response will cause the whole SubSectionAdmin singleton to change its exclude property.

The way to ensure that fields are excluded for each request is to do something like:

 class SubSectionAdmin(admin.ModelAdmin): # ... def get_form(self, request, obj=None, **kwargs): """Override the get_form and extend the 'exclude' keyword arg""" if obj: kwargs.update({ 'exclude': getattr(kwargs, 'exclude', tuple()) + ('field',), }) return super(SubSectionAdmin, self).get_form(request, obj, **kwargs) 

which will simply inform the form to exclude these additional fields.

Not sure how this will behave if the required field is excluded ...

+10
source share

Setting up self.exclude does, as @ steve-ike mentions, make the whole SubSectionAdmin singleton change its exclude property. Singleton is a class that will use the same instance each time an instance of the class is created, so an instance is created only the first time the constructor is used, and subsequent use of the constructor returns the same instance. A more detailed description can be found on the wiki page. This means that if you write code to exclude the field when changing, it will matter that if you first add the element, it will be there, but if you open the element for change, this field will be excluded for your next visits to the add page .

The easiest way to achieve the behavior of each request is to use get_fields and check the obj argument, which is None if we add an object, and an instance of an object if we change an object. The get_fields method is available from Django 1.7.

 class SubSectionAdmin(admin.ModelAdmin): def get_fields(self, request, obj=None): fields = super(SubSectionAdmin, self).get_fields(request, obj) if obj: # obj will be None on the add page, and something on change pages fields.remove('field') return fields 

Update:

Note that get_fields may return a tuple, so you may need to convert fields to a list to remove items. You may also encounter an error if the name of the field you are trying to delete is not in the list. Therefore, in some cases, when you have other factors that exclude fields, it is better to create a set of exceptions and delete using a list comprehension:

 class SubSectionAdmin(admin.ModelAdmin): def get_fields(self, request, obj=None): fields = list(super(SubSectionAdmin, self).get_fields(request, obj)) exclude_set = set() if obj: # obj will be None on the add page, and something on change pages exclude_set.add('field') return [f for f in fields if f not in exclude_set] 

Alternatively, you can also do a deepcopy result in the get_fieldsets method, which in other cases can give you access to a better context to exclude material. Most obviously, this will be useful if you need to act with the name fieldset. Also, this is the only way to go if you really use fields , as this will omit the get_fields call.

 from copy import deepcopy class SubSectionAdmin(admin.ModelAdmin): def get_fieldsets(self, request, obj=None): """Custom override to exclude fields""" fieldsets = deepcopy(super(SubSectionAdmin, self).get_fieldsets(request, obj)) # Append excludes here instead of using self.exclude. # When fieldsets are defined for the user admin, so self.exclude is ignored. exclude = () if not request.user.is_superuser: exclude += ('accepted_error_margin_alert', 'accepted_error_margin_warning') # Iterate fieldsets for fieldset in fieldsets: fieldset_fields = fieldset[1]['fields'] # Remove excluded fields from the fieldset for exclude_field in exclude: if exclude_field in fieldset_fields: fieldset_fields = tuple(field for field in fieldset_fields if field != exclude_field) # Filter fieldset[1]['fields'] = fieldset_fields # Store new tuple return fieldsets 
+4
source share

The approach below has the advantage that it does not override the property of an exclude object; instead, it is reset based on each type of request

 class SubSectionAdmin(admin.ModelAdmin): add_exclude = ('field1', 'field2') edit_exclude = ('field2',) def add_view(self, *args, **kwargs): self.exclude = getattr(self, 'add_exclude', ()) return super(SubSectionAdmin, self).add_view(*args, **kwargs) def change_view(self, *args, **kwargs): self.exclude = getattr(self, 'edit_exclude', ()) return super(SubSectionAdmin, self).change_view(*args, **kwargs) 
0
source share

All Articles