Loading django/forms/extras/widgets.py +20 −7 Original line number Diff line number Diff line Loading @@ -64,9 +64,22 @@ class SelectDateWidget(Widget): else: self.months = MONTHS # 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: year_val, month_val, day_val = value.year, value.month, value.day Loading @@ -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(): Loading Loading @@ -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) Loading docs/ref/forms/widgets.txt +15 −4 Original line number Diff line number Diff line Loading @@ -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")) tests/forms_tests/tests/test_extra.py +66 −5 Original line number Diff line number Diff line Loading @@ -297,11 +297,6 @@ class FormsExtraTestCase(TestCase, AssertFormErrorsMixin): <option value="2013">2013</option> </select>""") w = SelectDateWidget(years=('2014',), empty_label='empty_label') # Rendering the default state with empty_label setted. self.assertInHTML('<option value="0">empty_label</option>', 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)) Loading @@ -325,6 +320,72 @@ class FormsExtraTestCase(TestCase, AssertFormErrorsMixin): d = GetDate({'mydate_month': '1', 'mydate_day': '1', 'mydate_year': '2010'}) self.assertTrue('<label for="id_mydate_month">' in d.as_p()) def test_selectdate_empty_label(self): 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) w = SelectDateWidget(years=('2014',), empty_label=('empty_year', 'empty_month', 'empty_day')) # Rendering the default state with empty_label tuple. self.assertHTMLEqual(w.render('mydate', ''), """<select name="mydate_month" id="id_mydate_month"> <option value="0">empty_month</option> <option value="1">January</option> <option value="2">February</option> <option value="3">March</option> <option value="4">April</option> <option value="5">May</option> <option value="6">June</option> <option value="7">July</option> <option value="8">August</option> <option value="9">September</option> <option value="10">October</option> <option value="11">November</option> <option value="12">December</option> </select> <select name="mydate_day" id="id_mydate_day"> <option value="0">empty_day</option> <option value="1">1</option> <option value="2">2</option> <option value="3">3</option> <option value="4">4</option> <option value="5">5</option> <option value="6">6</option> <option value="7">7</option> <option value="8">8</option> <option value="9">9</option> <option value="10">10</option> <option value="11">11</option> <option value="12">12</option> <option value="13">13</option> <option value="14">14</option> <option value="15">15</option> <option value="16">16</option> <option value="17">17</option> <option value="18">18</option> <option value="19">19</option> <option value="20">20</option> <option value="21">21</option> <option value="22">22</option> <option value="23">23</option> <option value="24">24</option> <option value="25">25</option> <option value="26">26</option> <option value="27">27</option> <option value="28">28</option> <option value="29">29</option> <option value="30">30</option> <option value="31">31</option> </select> <select name="mydate_year" id="id_mydate_year"> <option value="0">empty_year</option> <option value="2014">2014</option> </select>""") self.assertRaisesMessage(ValueError, 'empty_label list/tuple must have 3 elements.', SelectDateWidget, years=('2014',), empty_label=('not enough', 'values')) def test_multiwidget(self): # MultiWidget and MultiValueField ############################################# # MultiWidgets are widgets composed of other widgets. They are usually Loading Loading
django/forms/extras/widgets.py +20 −7 Original line number Diff line number Diff line Loading @@ -64,9 +64,22 @@ class SelectDateWidget(Widget): else: self.months = MONTHS # 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: year_val, month_val, day_val = value.year, value.month, value.day Loading @@ -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(): Loading Loading @@ -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) Loading
docs/ref/forms/widgets.txt +15 −4 Original line number Diff line number Diff line Loading @@ -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"))
tests/forms_tests/tests/test_extra.py +66 −5 Original line number Diff line number Diff line Loading @@ -297,11 +297,6 @@ class FormsExtraTestCase(TestCase, AssertFormErrorsMixin): <option value="2013">2013</option> </select>""") w = SelectDateWidget(years=('2014',), empty_label='empty_label') # Rendering the default state with empty_label setted. self.assertInHTML('<option value="0">empty_label</option>', 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)) Loading @@ -325,6 +320,72 @@ class FormsExtraTestCase(TestCase, AssertFormErrorsMixin): d = GetDate({'mydate_month': '1', 'mydate_day': '1', 'mydate_year': '2010'}) self.assertTrue('<label for="id_mydate_month">' in d.as_p()) def test_selectdate_empty_label(self): 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) w = SelectDateWidget(years=('2014',), empty_label=('empty_year', 'empty_month', 'empty_day')) # Rendering the default state with empty_label tuple. self.assertHTMLEqual(w.render('mydate', ''), """<select name="mydate_month" id="id_mydate_month"> <option value="0">empty_month</option> <option value="1">January</option> <option value="2">February</option> <option value="3">March</option> <option value="4">April</option> <option value="5">May</option> <option value="6">June</option> <option value="7">July</option> <option value="8">August</option> <option value="9">September</option> <option value="10">October</option> <option value="11">November</option> <option value="12">December</option> </select> <select name="mydate_day" id="id_mydate_day"> <option value="0">empty_day</option> <option value="1">1</option> <option value="2">2</option> <option value="3">3</option> <option value="4">4</option> <option value="5">5</option> <option value="6">6</option> <option value="7">7</option> <option value="8">8</option> <option value="9">9</option> <option value="10">10</option> <option value="11">11</option> <option value="12">12</option> <option value="13">13</option> <option value="14">14</option> <option value="15">15</option> <option value="16">16</option> <option value="17">17</option> <option value="18">18</option> <option value="19">19</option> <option value="20">20</option> <option value="21">21</option> <option value="22">22</option> <option value="23">23</option> <option value="24">24</option> <option value="25">25</option> <option value="26">26</option> <option value="27">27</option> <option value="28">28</option> <option value="29">29</option> <option value="30">30</option> <option value="31">31</option> </select> <select name="mydate_year" id="id_mydate_year"> <option value="0">empty_year</option> <option value="2014">2014</option> </select>""") self.assertRaisesMessage(ValueError, 'empty_label list/tuple must have 3 elements.', SelectDateWidget, years=('2014',), empty_label=('not enough', 'values')) def test_multiwidget(self): # MultiWidget and MultiValueField ############################################# # MultiWidgets are widgets composed of other widgets. They are usually Loading