mirror of
				https://github.com/django/django.git
				synced 2025-10-31 01:25:32 +00:00 
			
		
		
		
	Refs #27186 -- Fixed model form default fallback for CheckboxSelectMultiple.
This commit is contained in:
		| @@ -817,6 +817,11 @@ class CheckboxSelectMultiple(RendererMixin, SelectMultiple): | ||||
|         # require all checkboxes to be checked instead of at least one. | ||||
|         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): | ||||
|     """ | ||||
|   | ||||
| @@ -280,10 +280,11 @@ foundation for custom widgets. | ||||
|         The method's result affects whether or not a field in a model form | ||||
|         :ref:`falls back to its default <topics-modelform-save>`. | ||||
|  | ||||
|         A special case is :class:`~django.forms.CheckboxInput`, which always | ||||
|         returns ``False`` because an unchecked checkbox doesn't appear in the | ||||
|         data of an HTML form submission, so it's unknown whether or not the | ||||
|         user actually submitted a value. | ||||
|         Special cases are :class:`~django.forms.CheckboxInput` and | ||||
|         :class:`~django.forms.CheckboxSelectMultiple`, which always return | ||||
|         ``False`` because an unchecked checkbox doesn't appear in the data of | ||||
|         an HTML form submission, so it's unknown whether or not the user | ||||
|         actually submitted a value. | ||||
|  | ||||
| ``MultiWidget`` | ||||
| --------------- | ||||
|   | ||||
| @@ -18,10 +18,10 @@ Bugfixes | ||||
| * Disabled system check for URL patterns beginning with a '/' when | ||||
|   ``APPEND_SLASH=False`` (:ticket:`27238`). | ||||
|  | ||||
| * Fixed model form ``default`` fallback for ``MultiWidget``, ``FileInput``, | ||||
|   ``SplitDateTimeWidget``, ``SelectDateWidget``, and ``SplitArrayWidget`` | ||||
|   (:ticket:`27186`). Custom widgets affected by this issue may need to | ||||
|   implement a :meth:`~django.forms.Widget.value_omitted_from_data` method. | ||||
| * Fixed model form ``default`` fallback for ``CheckboxSelectMultiple``, | ||||
|   ``MultiWidget``, ``FileInput``, ``SplitDateTimeWidget``, ``SelectDateWidget``, | ||||
|   and ``SplitArrayWidget`` (:ticket:`27186`). Custom widgets affected by this | ||||
|   issue should implement :meth:`~django.forms.Widget.value_omitted_from_data`. | ||||
|  | ||||
| * Fixed a crash in ``runserver`` logging during a "Broken pipe" error | ||||
|   (:ticket:`27271`). | ||||
|   | ||||
| @@ -337,7 +337,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 | ||||
| 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 | ||||
| :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 | ||||
| ``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 | ||||
|   | ||||
| @@ -120,3 +120,8 @@ class CheckboxSelectMultipleTest(WidgetTest): | ||||
|         self.assertIs(widget.use_required_attribute(None), False) | ||||
|         self.assertIs(widget.use_required_attribute([]), 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) | ||||
|   | ||||
| @@ -601,6 +601,22 @@ class ModelFormBaseTest(TestCase): | ||||
|         self.assertIsInstance(mf1.fields['active'].widget, forms.CheckboxInput) | ||||
|         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): | ||||
|         class PubForm(forms.ModelForm): | ||||
|             prefix = 'form-prefix' | ||||
| @@ -651,7 +667,7 @@ class ModelFormBaseTest(TestCase): | ||||
|         m2 = mf2.save(commit=False) | ||||
|         self.assertEqual(m2.file.name, 'name') | ||||
|  | ||||
|     def test_selectdatewidget(self): | ||||
|     def test_default_selectdatewidget(self): | ||||
|         class PubForm(forms.ModelForm): | ||||
|             date_published = forms.DateField(required=False, widget=forms.SelectDateWidget) | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user