mirror of
				https://github.com/django/django.git
				synced 2025-10-31 09:41:08 +00:00 
			
		
		
		
	Fixed #29036 -- Fixed HTML5 required validation on SelectDateWidget if the attribute is added by JavaScript.
Thanks Tim Graham for the initial patch.
This commit is contained in:
		
				
					committed by
					
						 Tim Graham
						Tim Graham
					
				
			
			
				
	
			
			
			
						parent
						
							5538729e4e
						
					
				
				
					commit
					fbc3c29e7c
				
			| @@ -911,7 +911,7 @@ class SelectDateWidget(Widget): | ||||
|     This also serves as an example of a Widget that has more than one HTML | ||||
|     element and hence implements value_from_datadict. | ||||
|     """ | ||||
|     none_value = (0, '---') | ||||
|     none_value = ('', '---') | ||||
|     month_field = '%s_month' | ||||
|     day_field = '%s_day' | ||||
|     year_field = '%s_year' | ||||
| @@ -941,12 +941,12 @@ class SelectDateWidget(Widget): | ||||
|             if not len(empty_label) == 3: | ||||
|                 raise ValueError('empty_label list/tuple must have 3 elements.') | ||||
|  | ||||
|             self.year_none_value = (0, empty_label[0]) | ||||
|             self.month_none_value = (0, empty_label[1]) | ||||
|             self.day_none_value = (0, empty_label[2]) | ||||
|             self.year_none_value = ('', empty_label[0]) | ||||
|             self.month_none_value = ('', empty_label[1]) | ||||
|             self.day_none_value = ('', empty_label[2]) | ||||
|         else: | ||||
|             if empty_label is not None: | ||||
|                 self.none_value = (0, empty_label) | ||||
|                 self.none_value = ('', empty_label) | ||||
|  | ||||
|             self.year_none_value = self.none_value | ||||
|             self.month_none_value = self.none_value | ||||
| @@ -1006,7 +1006,9 @@ class SelectDateWidget(Widget): | ||||
|         elif isinstance(value, str): | ||||
|             match = self.date_re.match(value) | ||||
|             if match: | ||||
|                 year, month, day = [int(val) for val in match.groups()] | ||||
|                 # Convert any zeros in the date to empty strings to match the | ||||
|                 # empty option value. | ||||
|                 year, month, day = [int(val) or '' for val in match.groups()] | ||||
|             elif settings.USE_L10N: | ||||
|                 input_format = get_format('DATE_INPUT_FORMATS')[0] | ||||
|                 try: | ||||
| @@ -1042,20 +1044,21 @@ class SelectDateWidget(Widget): | ||||
|         y = data.get(self.year_field % name) | ||||
|         m = data.get(self.month_field % name) | ||||
|         d = data.get(self.day_field % name) | ||||
|         if y == m == d == "0": | ||||
|         if y == m == d == '': | ||||
|             return None | ||||
|         if y and m and d: | ||||
|         if y is not None and m is not None and d is not None: | ||||
|             if settings.USE_L10N: | ||||
|                 input_format = get_format('DATE_INPUT_FORMATS')[0] | ||||
|                 try: | ||||
|                     date_value = datetime.date(int(y), int(m), int(d)) | ||||
|                 except ValueError: | ||||
|                     return '%s-%s-%s' % (y, m, d) | ||||
|                     pass | ||||
|                 else: | ||||
|                     date_value = datetime_safe.new_date(date_value) | ||||
|                     return date_value.strftime(input_format) | ||||
|             else: | ||||
|                 return '%s-%s-%s' % (y, m, d) | ||||
|             # Return pseudo-ISO dates with zeros for any unselected values, | ||||
|             # e.g. '2017-0-23'. | ||||
|             return '%s-%s-%s' % (y or 0, m or 0, d or 0) | ||||
|         return data.get(name) | ||||
|  | ||||
|     def value_omitted_from_data(self, data, files, name): | ||||
|   | ||||
| @@ -265,6 +265,10 @@ Miscellaneous | ||||
|   elements, e.g. ``<br>``. This is incompatible within XHTML, although some | ||||
|   widgets already used aspects of HTML5 such as boolean attributes. | ||||
|  | ||||
| * The value of :class:`~django.forms.SelectDateWidget`'s empty options is | ||||
|   changed from 0 to an empty string, which mainly may require some adjustments | ||||
|   in tests that compare HTML. | ||||
|  | ||||
| .. _deprecated-features-2.1: | ||||
|  | ||||
| Features deprecated in 2.1 | ||||
|   | ||||
| @@ -18,7 +18,7 @@ class SelectDateWidgetTest(WidgetTest): | ||||
|         self.check_html(self.widget, 'mydate', '', html=( | ||||
|             """ | ||||
|             <select name="mydate_month" id="id_mydate_month"> | ||||
|                 <option value="0">---</option> | ||||
|                 <option selected value="">---</option> | ||||
|                 <option value="1">January</option> | ||||
|                 <option value="2">February</option> | ||||
|                 <option value="3">March</option> | ||||
| @@ -34,7 +34,7 @@ class SelectDateWidgetTest(WidgetTest): | ||||
|             </select> | ||||
|  | ||||
|             <select name="mydate_day" id="id_mydate_day"> | ||||
|                 <option value="0">---</option> | ||||
|                 <option selected value="">---</option> | ||||
|                 <option value="1">1</option> | ||||
|                 <option value="2">2</option> | ||||
|                 <option value="3">3</option> | ||||
| @@ -69,7 +69,7 @@ class SelectDateWidgetTest(WidgetTest): | ||||
|             </select> | ||||
|  | ||||
|             <select name="mydate_year" id="id_mydate_year"> | ||||
|                 <option value="0">---</option> | ||||
|                 <option selected value="">---</option> | ||||
|                 <option value="2007">2007</option> | ||||
|                 <option value="2008">2008</option> | ||||
|                 <option value="2009">2009</option> | ||||
| @@ -97,7 +97,7 @@ class SelectDateWidgetTest(WidgetTest): | ||||
|         self.check_html(self.widget, 'mydate', '2010-04-15', html=( | ||||
|             """ | ||||
|             <select name="mydate_month" id="id_mydate_month"> | ||||
|                 <option value="0">---</option> | ||||
|                 <option value="">---</option> | ||||
|                 <option value="1">January</option> | ||||
|                 <option value="2">February</option> | ||||
|                 <option value="3">March</option> | ||||
| @@ -113,7 +113,7 @@ class SelectDateWidgetTest(WidgetTest): | ||||
|             </select> | ||||
|  | ||||
|             <select name="mydate_day" id="id_mydate_day"> | ||||
|                 <option value="0">---</option> | ||||
|                 <option value="">---</option> | ||||
|                 <option value="1">1</option> | ||||
|                 <option value="2">2</option> | ||||
|                 <option value="3">3</option> | ||||
| @@ -148,7 +148,7 @@ class SelectDateWidgetTest(WidgetTest): | ||||
|             </select> | ||||
|  | ||||
|             <select name="mydate_year" id="id_mydate_year"> | ||||
|                 <option value="0">---</option> | ||||
|                 <option value="">---</option> | ||||
|                 <option value="2007">2007</option> | ||||
|                 <option value="2008">2008</option> | ||||
|                 <option value="2009">2009</option> | ||||
| @@ -176,7 +176,7 @@ class SelectDateWidgetTest(WidgetTest): | ||||
|         self.check_html(self.widget, 'mydate', '2010-02-31', html=( | ||||
|             """ | ||||
|             <select name="mydate_month" id="id_mydate_month"> | ||||
|                 <option value="0">---</option> | ||||
|                 <option value="">---</option> | ||||
|                 <option value="1">January</option> | ||||
|                 <option value="2" selected>February</option> | ||||
|                 <option value="3">March</option> | ||||
| @@ -192,7 +192,7 @@ class SelectDateWidgetTest(WidgetTest): | ||||
|             </select> | ||||
|  | ||||
|             <select name="mydate_day" id="id_mydate_day"> | ||||
|                 <option value="0">---</option> | ||||
|                 <option value="">---</option> | ||||
|                 <option value="1">1</option> | ||||
|                 <option value="2">2</option> | ||||
|                 <option value="3">3</option> | ||||
| @@ -227,7 +227,7 @@ class SelectDateWidgetTest(WidgetTest): | ||||
|             </select> | ||||
|  | ||||
|             <select name="mydate_year" id="id_mydate_year"> | ||||
|                 <option value="0">---</option> | ||||
|                 <option value="">---</option> | ||||
|                 <option value="2007">2007</option> | ||||
|                 <option value="2008">2008</option> | ||||
|                 <option value="2009">2009</option> | ||||
| @@ -247,7 +247,7 @@ class SelectDateWidgetTest(WidgetTest): | ||||
|         self.check_html(widget, 'mydate', '', html=( | ||||
|             """ | ||||
|             <select name="mydate_month" id="id_mydate_month"> | ||||
|                 <option value="0">---</option> | ||||
|                 <option selected value="">---</option> | ||||
|                 <option value="1">Jan.</option> | ||||
|                 <option value="2">Feb.</option> | ||||
|                 <option value="3">March</option> | ||||
| @@ -263,7 +263,7 @@ class SelectDateWidgetTest(WidgetTest): | ||||
|             </select> | ||||
|  | ||||
|             <select name="mydate_day" id="id_mydate_day"> | ||||
|                 <option value="0">---</option> | ||||
|                 <option selected value="">---</option> | ||||
|                 <option value="1">1</option> | ||||
|                 <option value="2">2</option> | ||||
|                 <option value="3">3</option> | ||||
| @@ -298,7 +298,7 @@ class SelectDateWidgetTest(WidgetTest): | ||||
|             </select> | ||||
|  | ||||
|             <select name="mydate_year" id="id_mydate_year"> | ||||
|                 <option value="0">---</option> | ||||
|                 <option selected value="">---</option> | ||||
|                 <option value="2013">2013</option> | ||||
|             </select> | ||||
|             """ | ||||
| @@ -318,7 +318,7 @@ class SelectDateWidgetTest(WidgetTest): | ||||
|         w = SelectDateWidget(years=('2014',), empty_label='empty_label') | ||||
|  | ||||
|         # Rendering the default state with empty_label setted as string. | ||||
|         self.assertInHTML('<option value="0">empty_label</option>', w.render('mydate', ''), count=3) | ||||
|         self.assertInHTML('<option selected value="">empty_label</option>', w.render('mydate', ''), count=3) | ||||
|  | ||||
|         w = SelectDateWidget(years=('2014',), empty_label=('empty_year', 'empty_month', 'empty_day')) | ||||
|  | ||||
| @@ -327,7 +327,7 @@ class SelectDateWidgetTest(WidgetTest): | ||||
|             w.render('mydate', ''), | ||||
|             """ | ||||
|             <select name="mydate_month" id="id_mydate_month"> | ||||
|                 <option value="0">empty_month</option> | ||||
|                 <option selected value="">empty_month</option> | ||||
|                 <option value="1">January</option> | ||||
|                 <option value="2">February</option> | ||||
|                 <option value="3">March</option> | ||||
| @@ -343,7 +343,7 @@ class SelectDateWidgetTest(WidgetTest): | ||||
|             </select> | ||||
|  | ||||
|             <select name="mydate_day" id="id_mydate_day"> | ||||
|                 <option value="0">empty_day</option> | ||||
|                 <option selected value="">empty_day</option> | ||||
|                 <option value="1">1</option> | ||||
|                 <option value="2">2</option> | ||||
|                 <option value="3">3</option> | ||||
| @@ -378,7 +378,7 @@ class SelectDateWidgetTest(WidgetTest): | ||||
|             </select> | ||||
|  | ||||
|             <select name="mydate_year" id="id_mydate_year"> | ||||
|                 <option value="0">empty_year</option> | ||||
|                 <option selected value="">empty_year</option> | ||||
|                 <option value="2014">2014</option> | ||||
|             </select> | ||||
|             """, | ||||
| @@ -402,7 +402,7 @@ class SelectDateWidgetTest(WidgetTest): | ||||
|             w.render('date', '13-08-2010'), | ||||
|             """ | ||||
|             <select name="date_day" id="id_date_day"> | ||||
|                 <option value="0">---</option> | ||||
|                 <option value="">---</option> | ||||
|                 <option value="1">1</option> | ||||
|                 <option value="2">2</option> | ||||
|                 <option value="3">3</option> | ||||
| @@ -437,7 +437,7 @@ class SelectDateWidgetTest(WidgetTest): | ||||
|             </select> | ||||
|  | ||||
|             <select name="date_month" id="id_date_month"> | ||||
|                 <option value="0">---</option> | ||||
|                 <option value="">---</option> | ||||
|                 <option value="1">januari</option> | ||||
|                 <option value="2">februari</option> | ||||
|                 <option value="3">maart</option> | ||||
| @@ -453,7 +453,7 @@ class SelectDateWidgetTest(WidgetTest): | ||||
|             </select> | ||||
|  | ||||
|             <select name="date_year" id="id_date_year"> | ||||
|                 <option value="0">---</option> | ||||
|                 <option value="">---</option> | ||||
|                 <option value="2007">2007</option> | ||||
|                 <option value="2008">2008</option> | ||||
|                 <option value="2009">2009</option> | ||||
| @@ -485,7 +485,7 @@ class SelectDateWidgetTest(WidgetTest): | ||||
|             '0-01-01', '0-01-0', '0-0-01', '0-0-0', | ||||
|         ] | ||||
|         for value in valid_formats: | ||||
|             year, month, day = (int(x) for x in value.split('-')) | ||||
|             year, month, day = (int(x) or '' for x in value.split('-')) | ||||
|             with self.subTest(value=value): | ||||
|                 self.assertEqual(self.widget.format_value(value), {'day': day, 'month': month, 'year': year}) | ||||
|  | ||||
| @@ -500,9 +500,9 @@ class SelectDateWidgetTest(WidgetTest): | ||||
|     def test_value_from_datadict(self): | ||||
|         tests = [ | ||||
|             (('2000', '12', '1'), '2000-12-1'), | ||||
|             (('0', '12', '1'), '0-12-1'), | ||||
|             (('2000', '0', '1'), '2000-0-1'), | ||||
|             (('2000', '12', '0'), '2000-12-0'), | ||||
|             (('', '12', '1'), '0-12-1'), | ||||
|             (('2000', '', '1'), '2000-0-1'), | ||||
|             (('2000', '12', ''), '2000-12-0'), | ||||
|             (('', '', '', ''), None), | ||||
|             ((None, '12', '1'), None), | ||||
|             (('2000', None, '1'), None), | ||||
| @@ -530,7 +530,7 @@ class SelectDateWidgetTest(WidgetTest): | ||||
|         self.check_html(widget, 'mydate', '', html=( | ||||
|             """ | ||||
|             <select name="mydate_month" id="id_mydate_month"> | ||||
|                 <option value="0">---</option> | ||||
|                 <option selected value="">---</option> | ||||
|                 <option value="1">January</option> | ||||
|                 <option value="2">February</option> | ||||
|                 <option value="3">March</option> | ||||
| @@ -545,7 +545,7 @@ class SelectDateWidgetTest(WidgetTest): | ||||
|                 <option value="12">December</option> | ||||
|             </select> | ||||
|             <select name="mydate_day" id="id_mydate_day"> | ||||
|                 <option value="0">---</option> | ||||
|                 <option selected value="">---</option> | ||||
|                 <option value="1">1</option> | ||||
|                 <option value="2">2</option> | ||||
|                 <option value="3">3</option> | ||||
| @@ -579,7 +579,7 @@ class SelectDateWidgetTest(WidgetTest): | ||||
|                 <option value="31">31</option> | ||||
|             </select> | ||||
|             <select name="mydate_year" id="id_mydate_year"> | ||||
|                 <option value="0">---</option> | ||||
|                 <option selected value="">---</option> | ||||
|                 <option value="2007">2007</option> | ||||
|             </select> | ||||
|             """ | ||||
|   | ||||
| @@ -443,7 +443,7 @@ class FormattingTests(SimpleTestCase): | ||||
|             self.assertEqual(datetime.date(2009, 12, 31), form2.cleaned_data['date_field']) | ||||
|             self.assertHTMLEqual( | ||||
|                 '<select name="mydate_month" id="id_mydate_month">' | ||||
|                 '<option value="0">---</option>' | ||||
|                 '<option value="">---</option>' | ||||
|                 '<option value="1">gener</option>' | ||||
|                 '<option value="2">febrer</option>' | ||||
|                 '<option value="3">mar\xe7</option>' | ||||
| @@ -458,7 +458,7 @@ class FormattingTests(SimpleTestCase): | ||||
|                 '<option value="12" selected>desembre</option>' | ||||
|                 '</select>' | ||||
|                 '<select name="mydate_day" id="id_mydate_day">' | ||||
|                 '<option value="0">---</option>' | ||||
|                 '<option value="">---</option>' | ||||
|                 '<option value="1">1</option>' | ||||
|                 '<option value="2">2</option>' | ||||
|                 '<option value="3">3</option>' | ||||
| @@ -492,7 +492,7 @@ class FormattingTests(SimpleTestCase): | ||||
|                 '<option value="31" selected>31</option>' | ||||
|                 '</select>' | ||||
|                 '<select name="mydate_year" id="id_mydate_year">' | ||||
|                 '<option value="0">---</option>' | ||||
|                 '<option value="">---</option>' | ||||
|                 '<option value="2009" selected>2009</option>' | ||||
|                 '<option value="2010">2010</option>' | ||||
|                 '<option value="2011">2011</option>' | ||||
| @@ -622,7 +622,7 @@ class FormattingTests(SimpleTestCase): | ||||
|             self.assertEqual(datetime.date(2009, 12, 31), form5.cleaned_data['date_field']) | ||||
|             self.assertHTMLEqual( | ||||
|                 '<select name="mydate_day" id="id_mydate_day">' | ||||
|                 '<option value="0">---</option>' | ||||
|                 '<option value="">---</option>' | ||||
|                 '<option value="1">1</option>' | ||||
|                 '<option value="2">2</option>' | ||||
|                 '<option value="3">3</option>' | ||||
| @@ -656,7 +656,7 @@ class FormattingTests(SimpleTestCase): | ||||
|                 '<option value="31" selected>31</option>' | ||||
|                 '</select>' | ||||
|                 '<select name="mydate_month" id="id_mydate_month">' | ||||
|                 '<option value="0">---</option>' | ||||
|                 '<option value="">---</option>' | ||||
|                 '<option value="1">gener</option>' | ||||
|                 '<option value="2">febrer</option>' | ||||
|                 '<option value="3">mar\xe7</option>' | ||||
| @@ -671,7 +671,7 @@ class FormattingTests(SimpleTestCase): | ||||
|                 '<option value="12" selected>desembre</option>' | ||||
|                 '</select>' | ||||
|                 '<select name="mydate_year" id="id_mydate_year">' | ||||
|                 '<option value="0">---</option>' | ||||
|                 '<option value="">---</option>' | ||||
|                 '<option value="2009" selected>2009</option>' | ||||
|                 '<option value="2010">2010</option>' | ||||
|                 '<option value="2011">2011</option>' | ||||
| @@ -690,7 +690,7 @@ class FormattingTests(SimpleTestCase): | ||||
|         with translation.override('ru', deactivate=True): | ||||
|             self.assertHTMLEqual( | ||||
|                 '<select name="mydate_day" id="id_mydate_day">' | ||||
|                 '<option value="0">---</option>' | ||||
|                 '<option value="">---</option>' | ||||
|                 '<option value="1">1</option>' | ||||
|                 '<option value="2">2</option>' | ||||
|                 '<option value="3">3</option>' | ||||
| @@ -724,7 +724,7 @@ class FormattingTests(SimpleTestCase): | ||||
|                 '<option value="31" selected>31</option>' | ||||
|                 '</select>' | ||||
|                 '<select name="mydate_month" id="id_mydate_month">' | ||||
|                 '<option value="0">---</option>' | ||||
|                 '<option value="">---</option>' | ||||
|                 '<option value="1">\u042f\u043d\u0432\u0430\u0440\u044c</option>' | ||||
|                 '<option value="2">\u0424\u0435\u0432\u0440\u0430\u043b\u044c</option>' | ||||
|                 '<option value="3">\u041c\u0430\u0440\u0442</option>' | ||||
| @@ -739,7 +739,7 @@ class FormattingTests(SimpleTestCase): | ||||
|                 '<option value="12" selected>\u0414\u0435\u043a\u0430\u0431\u0440\u044c</option>' | ||||
|                 '</select>' | ||||
|                 '<select name="mydate_year" id="id_mydate_year">' | ||||
|                 '<option value="0">---</option>' | ||||
|                 '<option value="">---</option>' | ||||
|                 '<option value="2009" selected>2009</option>' | ||||
|                 '<option value="2010">2010</option>' | ||||
|                 '<option value="2011">2011</option>' | ||||
| @@ -819,7 +819,7 @@ class FormattingTests(SimpleTestCase): | ||||
|             self.assertEqual(datetime.date(2009, 12, 31), form6.cleaned_data['date_field']) | ||||
|             self.assertHTMLEqual( | ||||
|                 '<select name="mydate_month" id="id_mydate_month">' | ||||
|                 '<option value="0">---</option>' | ||||
|                 '<option value="">---</option>' | ||||
|                 '<option value="1">January</option>' | ||||
|                 '<option value="2">February</option>' | ||||
|                 '<option value="3">March</option>' | ||||
| @@ -834,7 +834,7 @@ class FormattingTests(SimpleTestCase): | ||||
|                 '<option value="12" selected>December</option>' | ||||
|                 '</select>' | ||||
|                 '<select name="mydate_day" id="id_mydate_day">' | ||||
|                 '<option value="0">---</option>' | ||||
|                 '<option value="">---</option>' | ||||
|                 '<option value="1">1</option>' | ||||
|                 '<option value="2">2</option>' | ||||
|                 '<option value="3">3</option>' | ||||
| @@ -868,7 +868,7 @@ class FormattingTests(SimpleTestCase): | ||||
|                 '<option value="31" selected>31</option>' | ||||
|                 '</select>' | ||||
|                 '<select name="mydate_year" id="id_mydate_year">' | ||||
|                 '<option value="0">---</option>' | ||||
|                 '<option value="">---</option>' | ||||
|                 '<option value="2009" selected>2009</option>' | ||||
|                 '<option value="2010">2010</option>' | ||||
|                 '<option value="2011">2011</option>' | ||||
|   | ||||
		Reference in New Issue
	
	Block a user