Fixed #27993 -- Fixed model form default fallback for SelectMultiple.
This commit is contained in:
parent
a0d29a9abe
commit
7d1e237753
|
@ -714,6 +714,11 @@ class SelectMultiple(Select):
|
||||||
getter = data.get
|
getter = data.get
|
||||||
return getter(name)
|
return getter(name)
|
||||||
|
|
||||||
|
def value_omitted_from_data(self, data, files, name):
|
||||||
|
# An unselected <select multiple> doesn't appear in POST data, so it's
|
||||||
|
# never known if the value is actually omitted.
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
class RadioSelect(ChoiceWidget):
|
class RadioSelect(ChoiceWidget):
|
||||||
input_type = 'radio'
|
input_type = 'radio'
|
||||||
|
|
|
@ -297,11 +297,12 @@ foundation for custom widgets.
|
||||||
The method's result affects whether or not a field in a model form
|
The method's result affects whether or not a field in a model form
|
||||||
:ref:`falls back to its default <topics-modelform-save>`.
|
:ref:`falls back to its default <topics-modelform-save>`.
|
||||||
|
|
||||||
Special cases are :class:`~django.forms.CheckboxInput` and
|
Special cases are :class:`~django.forms.CheckboxInput`,
|
||||||
:class:`~django.forms.CheckboxSelectMultiple`, which always return
|
:class:`~django.forms.CheckboxSelectMultiple`, and
|
||||||
``False`` because an unchecked checkbox doesn't appear in the data of
|
:class:`~django.forms.SelectMultiple`, which always return
|
||||||
an HTML form submission, so it's unknown whether or not the user
|
``False`` because an unchecked checkbox and unselected
|
||||||
actually submitted a value.
|
``<select multiple>`` don't appear in the data of an HTML form
|
||||||
|
submission, so it's unknown whether or not the user submitted a value.
|
||||||
|
|
||||||
.. method:: use_required_attribute(initial)
|
.. method:: use_required_attribute(initial)
|
||||||
|
|
||||||
|
|
|
@ -11,3 +11,6 @@ Bugfixes
|
||||||
|
|
||||||
* Made admin's ``RelatedFieldWidgetWrapper`` use the wrapped widget's
|
* Made admin's ``RelatedFieldWidgetWrapper`` use the wrapped widget's
|
||||||
``value_omitted_from_data()`` method (:ticket:`27905`).
|
``value_omitted_from_data()`` method (:ticket:`27905`).
|
||||||
|
|
||||||
|
* Fixed model form ``default`` fallback for ``SelectMultiple``
|
||||||
|
(:ticket:`27993`).
|
||||||
|
|
|
@ -335,12 +335,14 @@ doesn't validate -- i.e., if ``form.errors`` evaluates to ``True``.
|
||||||
If an optional field doesn't appear in the form's data, the resulting model
|
If an optional field doesn't appear in the form's data, the resulting model
|
||||||
instance uses the model field :attr:`~django.db.models.Field.default`, if
|
instance uses the model field :attr:`~django.db.models.Field.default`, if
|
||||||
there is one, for that field. This behavior doesn't apply to fields that use
|
there is one, for that field. This behavior doesn't apply to fields that use
|
||||||
:class:`~django.forms.CheckboxInput` and
|
:class:`~django.forms.CheckboxInput`,
|
||||||
:class:`~django.forms.CheckboxSelectMultiple` (or any custom widget whose
|
:class:`~django.forms.CheckboxSelectMultiple`, or
|
||||||
|
:class:`~django.forms.SelectMultiple` (or any custom widget whose
|
||||||
:meth:`~django.forms.Widget.value_omitted_from_data` method always returns
|
:meth:`~django.forms.Widget.value_omitted_from_data` method always returns
|
||||||
``False``) since an unchecked checkbox doesn't appear in the data of an HTML
|
``False``) since an unchecked checkbox and unselected ``<select multiple>``
|
||||||
form submission. Use a custom form field or widget if you're designing an API
|
don't appear in the data of an HTML form submission. Use a custom form field or
|
||||||
and want the default fallback for a :class:`~django.db.models.BooleanField`.
|
widget if you're designing an API and want the default fallback behavior for a
|
||||||
|
field that uses one of these widgets.
|
||||||
|
|
||||||
This ``save()`` method accepts an optional ``commit`` keyword argument, which
|
This ``save()`` method accepts an optional ``commit`` keyword argument, which
|
||||||
accepts either ``True`` or ``False``. If you call ``save()`` with
|
accepts either ``True`` or ``False``. If you call ``save()`` with
|
||||||
|
|
|
@ -123,3 +123,8 @@ class SelectMultipleTest(WidgetTest):
|
||||||
</optgroup>
|
</optgroup>
|
||||||
</select>"""
|
</select>"""
|
||||||
))
|
))
|
||||||
|
|
||||||
|
def test_value_omitted_from_data(self):
|
||||||
|
widget = self.widget(choices=self.beatles)
|
||||||
|
self.assertIs(widget.value_omitted_from_data({}, {}, 'field'), False)
|
||||||
|
self.assertIs(widget.value_omitted_from_data({'field': 'value'}, {}, 'field'), False)
|
||||||
|
|
|
@ -614,6 +614,22 @@ class ModelFormBaseTest(TestCase):
|
||||||
self.assertEqual(m1.mode, '')
|
self.assertEqual(m1.mode, '')
|
||||||
self.assertEqual(m1._meta.get_field('mode').get_default(), 'di')
|
self.assertEqual(m1._meta.get_field('mode').get_default(), 'di')
|
||||||
|
|
||||||
|
def test_default_not_populated_on_selectmultiple(self):
|
||||||
|
class PubForm(forms.ModelForm):
|
||||||
|
mode = forms.CharField(required=False, widget=forms.SelectMultiple)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = PublicationDefaults
|
||||||
|
fields = ('mode',)
|
||||||
|
|
||||||
|
# Empty data doesn't use the model default because an unselected
|
||||||
|
# SelectMultiple doesn't have a value in HTML form submission.
|
||||||
|
mf1 = PubForm({})
|
||||||
|
self.assertEqual(mf1.errors, {})
|
||||||
|
m1 = mf1.save(commit=False)
|
||||||
|
self.assertEqual(m1.mode, '')
|
||||||
|
self.assertEqual(m1._meta.get_field('mode').get_default(), 'di')
|
||||||
|
|
||||||
def test_prefixed_form_with_default_field(self):
|
def test_prefixed_form_with_default_field(self):
|
||||||
class PubForm(forms.ModelForm):
|
class PubForm(forms.ModelForm):
|
||||||
prefix = 'form-prefix'
|
prefix = 'form-prefix'
|
||||||
|
|
Loading…
Reference in New Issue