10👍
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)
18👍
orwellian’s answer will make the whole SubSectionAdmin singleton change its exclude property.
A way to ensure that fields are excluded on a per-request basis 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 just inform the Form to exclude those extra fields.
Not sure how this will behave given a required field being excluded…
- Get only certain fields of related object in Django
- Django REST framework Group by fields and add extra contents
- Django: Filtering on the related object, removing duplicates from the result
- Saving profile with registration in Django-Registration
- Refresh <div> element generated by a django template
14👍
Setting self.exclude
does as @steve-pike mentions, make the whole SubSectionAdmin
singleton change its exclude property.
A singleton is a class that will reuse the same instance every time the class is instantiated, so an instance is only created on the first use of the constructor, and subsequent use of the constructor will return the same instance. See the wiki page for a more indept description.
This means that if you write code to exclude the field on change it will have the implication that if you first add an item, the field will be there, but if you open an item for change, the field will be excluded for your following visits to the add page.
The simplest way to achieve a per request behaviour, is to use get_fields
and test on the obj
argument, which is None
if we are adding an object, and an instance of an object if we are changing 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:
Please note that get_fields
may return a tuple, so you may need to convert fields
into a list to remove elements.
You may also encounter an error if the field name you try to remove is not in the list. Therefore it may, in some cases where you have other factors that exclude fields, be better to build a set of excludes and remove 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 make a deepcopy
of the result in the get_fieldsets
method, which in other use cases may give you access to better context for excluding stuff. Most obviously this will be useful if you need to act on the fieldset name. Also, this is the only way to go if you actually use fieldsets since that will omit the call to get_fields
.
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
- Django Rest Framework create user and user profile
- What are the django-celery (djcelery) tables for?
- Django's CachedStaticFilesStorage not hashing file urls
- Django – Rendering Inclusion Tag from a View
- How to create charts with Plotly on Django?
1👍
The approach below has the advantage of not overriding the object wide exclude
property; 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👍
I believe you can override get_fieldsets
method of ModeAdmin
class. See the example below, in the code example below, I only want to display country
field in the form when adding a new country, In order to check if object is being added, we simply need to check if obj == None
, I am specifying the fields I need. Now otherwise obj != None
means existing object is being changed, so you can specify which fields you want to exclude from the change form.
def get_fieldsets(self, request: HttpRequest, obj=None):
fieldset = super().get_fieldsets(request, obj=obj)
if obj == None: # obj is None when you are adding new object.
fieldset[0][1]["fields"] = ["country"]
else:
fieldset[0][1]["fields"] = [
f.name
for f in self.model._meta.fields
if f.name not in ["id", "country"]
]
return fieldset
- How to unit test methods inside django's class based views?
- TimeField format in Django template
- Django how to turn off warning
- How do I tell django-nose where my tests are?
- Django QuerySet Custom Ordering by ID
0👍
You can override the get_exclude
method of the admin.ModelAdmin class:
def get_exclude(self, request, obj):
if "change" in request.path.split("/"):
return [
"fields",
"to",
"exclude",
]
return super().get_exclude(request, obj)
I think this is cleaner than the provided answers. It doesn’t override the exclude
field of the Class explicitly, but rather only contextually provides the fields you wish to exclude depending on what view you’re on.
- Django's {{ csrf_token }} is outputting the token value only, without the hidden input markup
- Django ModuleNotFoundError
- Obtain the first part of an URL from Django template
- Calling a function in Django after saving a model