From 7e2c87809ca601b7290203dd54ba3e9f90a702bd Mon Sep 17 00:00:00 2001 From: gyx1000 Date: Thu, 29 May 2014 17:15:01 +0200 Subject: [PATCH] Fixed #22684 -- Amended SelectDateWidget.empty_label to accept a tuple of values. Thanks danielsamuels for the report --- django/forms/extras/widgets.py | 27 +++++++--- docs/ref/forms/widgets.txt | 19 +++++-- tests/forms_tests/tests/test_extra.py | 71 +++++++++++++++++++++++++-- 3 files changed, 101 insertions(+), 16 deletions(-) diff --git a/django/forms/extras/widgets.py b/django/forms/extras/widgets.py index 09d22b0fb5..0d63b177f7 100644 --- a/django/forms/extras/widgets.py +++ b/django/forms/extras/widgets.py @@ -64,8 +64,21 @@ class SelectDateWidget(Widget): else: self.months = MONTHS - if empty_label is not None: - self.none_value = (0, empty_label) + # Optional string, list, or tuple to use as empty_label. + if isinstance(empty_label, (list, tuple)): + 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]) + else: + if empty_label is not None: + self.none_value = (0, empty_label) + + self.year_none_value = self.none_value + self.month_none_value = self.none_value + self.day_none_value = self.none_value def render(self, name, value, attrs=None): try: @@ -86,11 +99,11 @@ class SelectDateWidget(Widget): year_val, month_val, day_val = [int(v) for v in match.groups()] html = {} choices = [(i, i) for i in self.years] - html['year'] = self.create_select(name, self.year_field, value, year_val, choices) + html['year'] = self.create_select(name, self.year_field, value, year_val, choices, self.year_none_value) choices = list(six.iteritems(self.months)) - html['month'] = self.create_select(name, self.month_field, value, month_val, choices) + html['month'] = self.create_select(name, self.month_field, value, month_val, choices, self.month_none_value) choices = [(i, i) for i in range(1, 32)] - html['day'] = self.create_select(name, self.day_field, value, day_val, choices) + html['day'] = self.create_select(name, self.day_field, value, day_val, choices, self.day_none_value) output = [] for field in _parse_date_fmt(): @@ -123,13 +136,13 @@ class SelectDateWidget(Widget): return '%s-%s-%s' % (y, m, d) return data.get(name, None) - def create_select(self, name, field, value, val, choices): + def create_select(self, name, field, value, val, choices, none_value): if 'id' in self.attrs: id_ = self.attrs['id'] else: id_ = 'id_%s' % name if not self.is_required: - choices.insert(0, self.none_value) + choices.insert(0, none_value) local_attrs = self.build_attrs(id=field % id_) s = Select(choices=choices) select_html = s.render(field % name, val, local_attrs) diff --git a/docs/ref/forms/widgets.txt b/docs/ref/forms/widgets.txt index cf309f0298..7ed235b9e3 100644 --- a/docs/ref/forms/widgets.txt +++ b/docs/ref/forms/widgets.txt @@ -787,9 +787,20 @@ Composite widgets .. versionadded:: 1.8 If the :class:`~django.forms.DateField` is not required, - :class:`SelectDateWidget` will have an empty choice at the top of - the list. You can change the text of this label - (which is ``---`` by default) with the ``empty_label`` attribute:: + :class:`SelectDateWidget` will have an empty choice at the top of the + list (which is ``---`` by default). You can change the text of this + label with the ``empty_label`` attribute. ``empty_label`` can be a + ``string``, ``list``, or ``tuple``. When a string is used, all select + boxes will each have an empty choice with this label. If ``empty_label`` + is a ``list`` or ``tuple`` of 3 string elements, the select boxes will + have their own custom label. The labels should be in this order + ``('year_label', 'month_label', 'day_label')``. - # A custom empty label + .. code-block:: python + + # A custom empty label with string field1 = forms.DateField(widget=SelectDateWidget(empty_label="Nothing")) + + # A custom empty label with tuple + field1 = forms.DateField(widget=SelectDateWidget( + empty_label=("Choose Year", "Choose Month", "Choose Day")) diff --git a/tests/forms_tests/tests/test_extra.py b/tests/forms_tests/tests/test_extra.py index 499db79014..3f6208fade 100644 --- a/tests/forms_tests/tests/test_extra.py +++ b/tests/forms_tests/tests/test_extra.py @@ -297,11 +297,6 @@ class FormsExtraTestCase(TestCase, AssertFormErrorsMixin): """) - w = SelectDateWidget(years=('2014',), empty_label='empty_label') - - # Rendering the default state with empty_label setted. - self.assertInHTML('', w.render('mydate', ''), count=3) - a = GetDate({'mydate_month': '4', 'mydate_day': '1', 'mydate_year': '2008'}) self.assertTrue(a.is_valid()) self.assertEqual(a.cleaned_data['mydate'], datetime.date(2008, 4, 1)) @@ -325,6 +320,72 @@ class FormsExtraTestCase(TestCase, AssertFormErrorsMixin): d = GetDate({'mydate_month': '1', 'mydate_day': '1', 'mydate_year': '2010'}) self.assertTrue('