mirror of
				https://github.com/django/django.git
				synced 2025-10-31 09:41:08 +00:00 
			
		
		
		
	[1.11.x] Fixed #27993 -- Fixed model form default fallback for SelectMultiple.
Backport of 7d1e237753 from master
			
			
This commit is contained in:
		| @@ -736,6 +736,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' | ||||||
|   | |||||||
| @@ -304,11 +304,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`). | ||||||
|   | |||||||
| @@ -337,12 +337,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. | ||||||
|  |  | ||||||
| .. versionchanged:: 1.10.1 | .. versionchanged:: 1.10.1 | ||||||
|  |  | ||||||
|   | |||||||
| @@ -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) | ||||||
|   | |||||||
| @@ -618,6 +618,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' | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user