[1.10.x] Refs #27186 -- Fixed model form default fallback for CheckboxSelectMultiple.
Backport of 87c5e7efeb
from master
This commit is contained in:
parent
fb9f396275
commit
f23c03ebc8
|
@ -812,6 +812,11 @@ class CheckboxSelectMultiple(RendererMixin, SelectMultiple):
|
||||||
# require all checkboxes to be checked instead of at least one.
|
# require all checkboxes to be checked instead of at least one.
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
def value_omitted_from_data(self, data, files, name):
|
||||||
|
# HTML checkboxes don't appear in POST data if not checked, so it's
|
||||||
|
# never known if the value is actually omitted.
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
class MultiWidget(Widget):
|
class MultiWidget(Widget):
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -281,10 +281,11 @@ 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>`.
|
||||||
|
|
||||||
A special case is :class:`~django.forms.CheckboxInput`, which always
|
Special cases are :class:`~django.forms.CheckboxInput` and
|
||||||
returns ``False`` because an unchecked checkbox doesn't appear in the
|
:class:`~django.forms.CheckboxSelectMultiple`, which always return
|
||||||
data of an HTML form submission, so it's unknown whether or not the
|
``False`` because an unchecked checkbox doesn't appear in the data of
|
||||||
user actually submitted a value.
|
an HTML form submission, so it's unknown whether or not the user
|
||||||
|
actually submitted a value.
|
||||||
|
|
||||||
``MultiWidget``
|
``MultiWidget``
|
||||||
---------------
|
---------------
|
||||||
|
|
|
@ -18,10 +18,10 @@ Bugfixes
|
||||||
* Disabled system check for URL patterns beginning with a '/' when
|
* Disabled system check for URL patterns beginning with a '/' when
|
||||||
``APPEND_SLASH=False`` (:ticket:`27238`).
|
``APPEND_SLASH=False`` (:ticket:`27238`).
|
||||||
|
|
||||||
* Fixed model form ``default`` fallback for ``MultiWidget``, ``FileInput``,
|
* Fixed model form ``default`` fallback for ``CheckboxSelectMultiple``,
|
||||||
``SplitDateTimeWidget``, ``SelectDateWidget``, and ``SplitArrayWidget``
|
``MultiWidget``, ``FileInput``, ``SplitDateTimeWidget``, ``SelectDateWidget``,
|
||||||
(:ticket:`27186`). Custom widgets affected by this issue may need to
|
and ``SplitArrayWidget`` (:ticket:`27186`). Custom widgets affected by this
|
||||||
implement a :meth:`~django.forms.Widget.value_omitted_from_data` method.
|
issue should implement :meth:`~django.forms.Widget.value_omitted_from_data`.
|
||||||
|
|
||||||
* Fixed a crash in ``runserver`` logging during a "Broken pipe" error
|
* Fixed a crash in ``runserver`` logging during a "Broken pipe" error
|
||||||
(:ticket:`27271`).
|
(:ticket:`27271`).
|
||||||
|
|
|
@ -335,7 +335,8 @@ 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` (or any custom widget whose
|
:class:`~django.forms.CheckboxInput` and
|
||||||
|
:class:`~django.forms.CheckboxSelectMultiple` (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 doesn't appear in the data of an HTML
|
||||||
form submission. Use a custom form field or widget if you're designing an API
|
form submission. Use a custom form field or widget if you're designing an API
|
||||||
|
|
|
@ -120,3 +120,8 @@ class CheckboxSelectMultipleTest(WidgetTest):
|
||||||
self.assertIs(widget.use_required_attribute(None), False)
|
self.assertIs(widget.use_required_attribute(None), False)
|
||||||
self.assertIs(widget.use_required_attribute([]), False)
|
self.assertIs(widget.use_required_attribute([]), False)
|
||||||
self.assertIs(widget.use_required_attribute(['J', 'P']), False)
|
self.assertIs(widget.use_required_attribute(['J', 'P']), False)
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
|
@ -585,6 +585,22 @@ class ModelFormBaseTest(TestCase):
|
||||||
self.assertIsInstance(mf1.fields['active'].widget, forms.CheckboxInput)
|
self.assertIsInstance(mf1.fields['active'].widget, forms.CheckboxInput)
|
||||||
self.assertIs(m1._meta.get_field('active').get_default(), True)
|
self.assertIs(m1._meta.get_field('active').get_default(), True)
|
||||||
|
|
||||||
|
def test_default_not_populated_on_checkboxselectmultiple(self):
|
||||||
|
class PubForm(forms.ModelForm):
|
||||||
|
mode = forms.CharField(required=False, widget=forms.CheckboxSelectMultiple)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = PublicationDefaults
|
||||||
|
fields = ('mode',)
|
||||||
|
|
||||||
|
# Empty data doesn't use the model default because an unchecked
|
||||||
|
# CheckboxSelectMultiple 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'
|
||||||
|
@ -635,7 +651,7 @@ class ModelFormBaseTest(TestCase):
|
||||||
m2 = mf2.save(commit=False)
|
m2 = mf2.save(commit=False)
|
||||||
self.assertEqual(m2.file.name, 'name')
|
self.assertEqual(m2.file.name, 'name')
|
||||||
|
|
||||||
def test_selectdatewidget(self):
|
def test_default_selectdatewidget(self):
|
||||||
class PubForm(forms.ModelForm):
|
class PubForm(forms.ModelForm):
|
||||||
date_published = forms.DateField(required=False, widget=forms.SelectDateWidget)
|
date_published = forms.DateField(required=False, widget=forms.SelectDateWidget)
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue