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 | ||||
|         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): | ||||
|     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 | ||||
|         :ref:`falls back to its default <topics-modelform-save>`. | ||||
|  | ||||
|         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. | ||||
|         Special cases are :class:`~django.forms.CheckboxInput`, | ||||
|         :class:`~django.forms.CheckboxSelectMultiple`, and | ||||
|         :class:`~django.forms.SelectMultiple`, which always return | ||||
|         ``False`` because an unchecked checkbox and unselected | ||||
|         ``<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) | ||||
|  | ||||
|   | ||||
| @@ -11,3 +11,6 @@ Bugfixes | ||||
|  | ||||
| * Made admin's ``RelatedFieldWidgetWrapper`` use the wrapped widget's | ||||
|   ``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 | ||||
| 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` and | ||||
| :class:`~django.forms.CheckboxSelectMultiple` (or any custom widget whose | ||||
| :class:`~django.forms.CheckboxInput`, | ||||
| :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 | ||||
| ``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 | ||||
| and want the default fallback for a :class:`~django.db.models.BooleanField`. | ||||
| ``False``) since an unchecked checkbox and unselected ``<select multiple>`` | ||||
| don't appear in the data of an HTML form submission. Use a custom form field or | ||||
| 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 | ||||
|  | ||||
|   | ||||
| @@ -123,3 +123,8 @@ class SelectMultipleTest(WidgetTest): | ||||
|             </optgroup> | ||||
|             </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._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): | ||||
|         class PubForm(forms.ModelForm): | ||||
|             prefix = 'form-prefix' | ||||
|   | ||||
		Reference in New Issue
	
	Block a user