Fixed #24908 -- Fixed duplicate readonly field rendering.
ModelAdmin added readonly_fields to exclude, but would not undeclare them if they were overridden.
This commit is contained in:
parent
60f795c060
commit
fedef7b2c6
|
@ -605,7 +605,8 @@ class ModelAdmin(BaseModelAdmin):
|
||||||
exclude = []
|
exclude = []
|
||||||
else:
|
else:
|
||||||
exclude = list(self.exclude)
|
exclude = list(self.exclude)
|
||||||
exclude.extend(self.get_readonly_fields(request, obj))
|
readonly_fields = self.get_readonly_fields(request, obj)
|
||||||
|
exclude.extend(readonly_fields)
|
||||||
if self.exclude is None and hasattr(self.form, '_meta') and self.form._meta.exclude:
|
if self.exclude is None and hasattr(self.form, '_meta') and self.form._meta.exclude:
|
||||||
# Take the custom ModelForm's Meta.exclude into account only if the
|
# Take the custom ModelForm's Meta.exclude into account only if the
|
||||||
# ModelAdmin doesn't define its own.
|
# ModelAdmin doesn't define its own.
|
||||||
|
@ -613,8 +614,16 @@ class ModelAdmin(BaseModelAdmin):
|
||||||
# if exclude is an empty list we pass None to be consistent with the
|
# if exclude is an empty list we pass None to be consistent with the
|
||||||
# default on modelform_factory
|
# default on modelform_factory
|
||||||
exclude = exclude or None
|
exclude = exclude or None
|
||||||
|
|
||||||
|
# Remove declared form fields which are in readonly_fields.
|
||||||
|
new_attrs = OrderedDict(
|
||||||
|
(f, None) for f in readonly_fields
|
||||||
|
if f in self.form.declared_fields
|
||||||
|
)
|
||||||
|
form = type(self.form.__name__, (self.form,), new_attrs)
|
||||||
|
|
||||||
defaults = {
|
defaults = {
|
||||||
"form": self.form,
|
"form": form,
|
||||||
"fields": fields,
|
"fields": fields,
|
||||||
"exclude": exclude,
|
"exclude": exclude,
|
||||||
"formfield_callback": partial(self.formfield_for_dbfield, request=request),
|
"formfield_callback": partial(self.formfield_for_dbfield, request=request),
|
||||||
|
|
|
@ -221,6 +221,37 @@ class ModelAdminTests(TestCase):
|
||||||
list(list(ma.get_formsets_with_inlines(request))[0][0]().forms[0].fields),
|
list(list(ma.get_formsets_with_inlines(request))[0][0]().forms[0].fields),
|
||||||
['main_band', 'opening_band', 'id', 'DELETE'])
|
['main_band', 'opening_band', 'id', 'DELETE'])
|
||||||
|
|
||||||
|
def test_custom_formfield_override_readonly(self):
|
||||||
|
class AdminBandForm(forms.ModelForm):
|
||||||
|
name = forms.CharField()
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
exclude = tuple()
|
||||||
|
model = Band
|
||||||
|
|
||||||
|
class BandAdmin(ModelAdmin):
|
||||||
|
form = AdminBandForm
|
||||||
|
readonly_fields = ['name']
|
||||||
|
|
||||||
|
ma = BandAdmin(Band, self.site)
|
||||||
|
|
||||||
|
# `name` shouldn't appear in base_fields because it's part of
|
||||||
|
# readonly_fields.
|
||||||
|
self.assertEqual(
|
||||||
|
list(ma.get_form(request).base_fields),
|
||||||
|
['bio', 'sign_date']
|
||||||
|
)
|
||||||
|
# But it should appear in get_fields()/fieldsets() so it can be
|
||||||
|
# displayed as read-only.
|
||||||
|
self.assertEqual(
|
||||||
|
list(ma.get_fields(request)),
|
||||||
|
['bio', 'sign_date', 'name']
|
||||||
|
)
|
||||||
|
self.assertEqual(
|
||||||
|
list(ma.get_fieldsets(request)),
|
||||||
|
[(None, {'fields': ['bio', 'sign_date', 'name']})]
|
||||||
|
)
|
||||||
|
|
||||||
def test_custom_form_meta_exclude(self):
|
def test_custom_form_meta_exclude(self):
|
||||||
"""
|
"""
|
||||||
Ensure that the custom ModelForm's `Meta.exclude` is overridden if
|
Ensure that the custom ModelForm's `Meta.exclude` is overridden if
|
||||||
|
|
Loading…
Reference in New Issue