Fixed #14496 -- Fixed conflict between ModelForm exclude and ModelAdmin readonly values. Thanks, Julien Phalip.
git-svn-id: http://code.djangoproject.com/svn/django/trunk@16602 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
e912edec20
commit
3d027b72eb
|
@ -437,6 +437,10 @@ class ModelAdmin(BaseModelAdmin):
|
||||||
else:
|
else:
|
||||||
exclude = list(self.exclude)
|
exclude = list(self.exclude)
|
||||||
exclude.extend(self.get_readonly_fields(request, obj))
|
exclude.extend(self.get_readonly_fields(request, obj))
|
||||||
|
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
|
||||||
|
# ModelAdmin doesn't define its own.
|
||||||
|
exclude.extend(self.form._meta.exclude)
|
||||||
# if exclude is an empty list we pass None to be consistant with the
|
# if exclude is an empty list we pass None to be consistant with the
|
||||||
# default on modelform_factory
|
# default on modelform_factory
|
||||||
exclude = exclude or None
|
exclude = exclude or None
|
||||||
|
@ -1343,6 +1347,10 @@ class InlineModelAdmin(BaseModelAdmin):
|
||||||
else:
|
else:
|
||||||
exclude = list(self.exclude)
|
exclude = list(self.exclude)
|
||||||
exclude.extend(self.get_readonly_fields(request, obj))
|
exclude.extend(self.get_readonly_fields(request, obj))
|
||||||
|
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
|
||||||
|
# InlineModelAdmin doesn't define its own.
|
||||||
|
exclude.extend(self.form._meta.exclude)
|
||||||
# if exclude is an empty list we use None, since that's the actual
|
# if exclude is an empty list we use None, since that's the actual
|
||||||
# default
|
# default
|
||||||
exclude = exclude or None
|
exclude = exclude or None
|
||||||
|
|
|
@ -313,6 +313,24 @@ subclass::
|
||||||
|
|
||||||
For an example see the section `Adding custom validation to the admin`_.
|
For an example see the section `Adding custom validation to the admin`_.
|
||||||
|
|
||||||
|
.. admonition:: Note
|
||||||
|
|
||||||
|
If your ``ModelForm`` and ``ModelAdmin`` both define an ``exclude``
|
||||||
|
option then ``ModelAdmin`` takes precedence::
|
||||||
|
|
||||||
|
class PersonForm(forms.ModelForm):
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = Person
|
||||||
|
exclude = ['name']
|
||||||
|
|
||||||
|
class PersonAdmin(admin.ModelAdmin):
|
||||||
|
exclude = ['age']
|
||||||
|
form = PersonForm
|
||||||
|
|
||||||
|
In the above example, the "age" field will be excluded but the "name"
|
||||||
|
field will be included in the generated form.
|
||||||
|
|
||||||
.. attribute:: ModelAdmin.formfield_overrides
|
.. attribute:: ModelAdmin.formfield_overrides
|
||||||
|
|
||||||
This provides a quick-and-dirty way to override some of the
|
This provides a quick-and-dirty way to override some of the
|
||||||
|
|
|
@ -120,6 +120,99 @@ class ModelAdminTests(TestCase):
|
||||||
self.assertEqual(ma.get_form(request).base_fields.keys(),
|
self.assertEqual(ma.get_form(request).base_fields.keys(),
|
||||||
['name'])
|
['name'])
|
||||||
|
|
||||||
|
def test_custom_form_meta_exclude_with_readonly(self):
|
||||||
|
"""
|
||||||
|
Ensure that the custom ModelForm's `Meta.exclude` is respected when
|
||||||
|
used in conjunction with `ModelAdmin.readonly_fields` and when no
|
||||||
|
`ModelAdmin.exclude` is defined.
|
||||||
|
Refs #14496.
|
||||||
|
"""
|
||||||
|
# First, with `ModelAdmin` -----------------------
|
||||||
|
|
||||||
|
class AdminBandForm(forms.ModelForm):
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = Band
|
||||||
|
exclude = ['bio']
|
||||||
|
|
||||||
|
class BandAdmin(ModelAdmin):
|
||||||
|
readonly_fields = ['name']
|
||||||
|
form = AdminBandForm
|
||||||
|
|
||||||
|
ma = BandAdmin(Band, self.site)
|
||||||
|
self.assertEqual(ma.get_form(request).base_fields.keys(),
|
||||||
|
['sign_date',])
|
||||||
|
|
||||||
|
# Then, with `InlineModelAdmin` -----------------
|
||||||
|
|
||||||
|
class AdminConcertForm(forms.ModelForm):
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = Concert
|
||||||
|
exclude = ['day']
|
||||||
|
|
||||||
|
class ConcertInline(TabularInline):
|
||||||
|
readonly_fields = ['transport']
|
||||||
|
form = AdminConcertForm
|
||||||
|
fk_name = 'main_band'
|
||||||
|
model = Concert
|
||||||
|
|
||||||
|
class BandAdmin(ModelAdmin):
|
||||||
|
inlines = [
|
||||||
|
ConcertInline
|
||||||
|
]
|
||||||
|
|
||||||
|
ma = BandAdmin(Band, self.site)
|
||||||
|
self.assertEqual(
|
||||||
|
list(ma.get_formsets(request))[0]().forms[0].fields.keys(),
|
||||||
|
['main_band', 'opening_band', 'id', 'DELETE',])
|
||||||
|
|
||||||
|
def test_custom_form_meta_exclude(self):
|
||||||
|
"""
|
||||||
|
Ensure that the custom ModelForm's `Meta.exclude` is overridden if
|
||||||
|
`ModelAdmin.exclude` or `InlineModelAdmin.exclude` are defined.
|
||||||
|
Refs #14496.
|
||||||
|
"""
|
||||||
|
# First, with `ModelAdmin` -----------------------
|
||||||
|
|
||||||
|
class AdminBandForm(forms.ModelForm):
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = Band
|
||||||
|
exclude = ['bio']
|
||||||
|
|
||||||
|
class BandAdmin(ModelAdmin):
|
||||||
|
exclude = ['name']
|
||||||
|
form = AdminBandForm
|
||||||
|
|
||||||
|
ma = BandAdmin(Band, self.site)
|
||||||
|
self.assertEqual(ma.get_form(request).base_fields.keys(),
|
||||||
|
['bio', 'sign_date',])
|
||||||
|
|
||||||
|
# Then, with `InlineModelAdmin` -----------------
|
||||||
|
|
||||||
|
class AdminConcertForm(forms.ModelForm):
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = Concert
|
||||||
|
exclude = ['day']
|
||||||
|
|
||||||
|
class ConcertInline(TabularInline):
|
||||||
|
exclude = ['transport']
|
||||||
|
form = AdminConcertForm
|
||||||
|
fk_name = 'main_band'
|
||||||
|
model = Concert
|
||||||
|
|
||||||
|
class BandAdmin(ModelAdmin):
|
||||||
|
inlines = [
|
||||||
|
ConcertInline
|
||||||
|
]
|
||||||
|
|
||||||
|
ma = BandAdmin(Band, self.site)
|
||||||
|
self.assertEqual(
|
||||||
|
list(ma.get_formsets(request))[0]().forms[0].fields.keys(),
|
||||||
|
['main_band', 'opening_band', 'day', 'id', 'DELETE',])
|
||||||
|
|
||||||
def test_custom_form_validation(self):
|
def test_custom_form_validation(self):
|
||||||
# If we specify a form, it should use it allowing custom validation to work
|
# If we specify a form, it should use it allowing custom validation to work
|
||||||
# properly. This won't, however, break any of the admin widgets or media.
|
# properly. This won't, however, break any of the admin widgets or media.
|
||||||
|
|
Loading…
Reference in New Issue