From fbc3c29e7cc5b3a3f62f1700af6ba474f05d59eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vlastimil=20Z=C3=ADma?= Date: Tue, 30 Jan 2018 10:33:13 +0100 Subject: [PATCH] Fixed #29036 -- Fixed HTML5 required validation on SelectDateWidget if the attribute is added by JavaScript. Thanks Tim Graham for the initial patch. --- django/forms/widgets.py | 25 +++++---- docs/releases/2.1.txt | 4 ++ .../widget_tests/test_selectdatewidget.py | 52 +++++++++---------- tests/i18n/tests.py | 24 ++++----- 4 files changed, 56 insertions(+), 49 deletions(-) diff --git a/django/forms/widgets.py b/django/forms/widgets.py index 0f861f00461..c0e3349aba0 100644 --- a/django/forms/widgets.py +++ b/django/forms/widgets.py @@ -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): diff --git a/docs/releases/2.1.txt b/docs/releases/2.1.txt index 03d80115d32..a2aa2e83794 100644 --- a/docs/releases/2.1.txt +++ b/docs/releases/2.1.txt @@ -265,6 +265,10 @@ Miscellaneous elements, e.g. ``
``. 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 diff --git a/tests/forms_tests/widget_tests/test_selectdatewidget.py b/tests/forms_tests/widget_tests/test_selectdatewidget.py index c0e82c69a02..1fe72ca8fbc 100644 --- a/tests/forms_tests/widget_tests/test_selectdatewidget.py +++ b/tests/forms_tests/widget_tests/test_selectdatewidget.py @@ -18,7 +18,7 @@ class SelectDateWidgetTest(WidgetTest): self.check_html(self.widget, 'mydate', '', html=( """ - + @@ -113,7 +113,7 @@ class SelectDateWidgetTest(WidgetTest): - + @@ -192,7 +192,7 @@ class SelectDateWidgetTest(WidgetTest): - + @@ -263,7 +263,7 @@ class SelectDateWidgetTest(WidgetTest): """ @@ -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('', w.render('mydate', ''), count=3) + self.assertInHTML('', 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', ''), """ """, @@ -402,7 +402,7 @@ class SelectDateWidgetTest(WidgetTest): w.render('date', '13-08-2010'), """ - + @@ -545,7 +545,7 @@ class SelectDateWidgetTest(WidgetTest): """ diff --git a/tests/i18n/tests.py b/tests/i18n/tests.py index 8eedf09d688..b9aa0cad55d 100644 --- a/tests/i18n/tests.py +++ b/tests/i18n/tests.py @@ -443,7 +443,7 @@ class FormattingTests(SimpleTestCase): self.assertEqual(datetime.date(2009, 12, 31), form2.cleaned_data['date_field']) self.assertHTMLEqual( '' '' '' - '' + '' '' '' '' @@ -656,7 +656,7 @@ class FormattingTests(SimpleTestCase): '' '' '' '' - '' + '' '' '' '' @@ -724,7 +724,7 @@ class FormattingTests(SimpleTestCase): '' '' '' '' - '' + '' '' '' '' @@ -834,7 +834,7 @@ class FormattingTests(SimpleTestCase): '' '' '' '