Fixed #22684 -- Amended SelectDateWidget.empty_label to accept a tuple of values.
Thanks danielsamuels for the report
This commit is contained in:
parent
fb9d8f0652
commit
7e2c87809c
|
@ -64,9 +64,22 @@ class SelectDateWidget(Widget):
|
||||||
else:
|
else:
|
||||||
self.months = MONTHS
|
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:
|
if empty_label is not None:
|
||||||
self.none_value = (0, empty_label)
|
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):
|
def render(self, name, value, attrs=None):
|
||||||
try:
|
try:
|
||||||
year_val, month_val, day_val = value.year, value.month, value.day
|
year_val, month_val, day_val = value.year, value.month, value.day
|
||||||
|
@ -86,11 +99,11 @@ class SelectDateWidget(Widget):
|
||||||
year_val, month_val, day_val = [int(v) for v in match.groups()]
|
year_val, month_val, day_val = [int(v) for v in match.groups()]
|
||||||
html = {}
|
html = {}
|
||||||
choices = [(i, i) for i in self.years]
|
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))
|
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)]
|
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 = []
|
output = []
|
||||||
for field in _parse_date_fmt():
|
for field in _parse_date_fmt():
|
||||||
|
@ -123,13 +136,13 @@ class SelectDateWidget(Widget):
|
||||||
return '%s-%s-%s' % (y, m, d)
|
return '%s-%s-%s' % (y, m, d)
|
||||||
return data.get(name, None)
|
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:
|
if 'id' in self.attrs:
|
||||||
id_ = self.attrs['id']
|
id_ = self.attrs['id']
|
||||||
else:
|
else:
|
||||||
id_ = 'id_%s' % name
|
id_ = 'id_%s' % name
|
||||||
if not self.is_required:
|
if not self.is_required:
|
||||||
choices.insert(0, self.none_value)
|
choices.insert(0, none_value)
|
||||||
local_attrs = self.build_attrs(id=field % id_)
|
local_attrs = self.build_attrs(id=field % id_)
|
||||||
s = Select(choices=choices)
|
s = Select(choices=choices)
|
||||||
select_html = s.render(field % name, val, local_attrs)
|
select_html = s.render(field % name, val, local_attrs)
|
||||||
|
|
|
@ -787,9 +787,20 @@ Composite widgets
|
||||||
.. versionadded:: 1.8
|
.. versionadded:: 1.8
|
||||||
|
|
||||||
If the :class:`~django.forms.DateField` is not required,
|
If the :class:`~django.forms.DateField` is not required,
|
||||||
:class:`SelectDateWidget` will have an empty choice at the top of
|
:class:`SelectDateWidget` will have an empty choice at the top of the
|
||||||
the list. You can change the text of this label
|
list (which is ``---`` by default). You can change the text of this
|
||||||
(which is ``---`` by default) with the ``empty_label`` attribute::
|
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"))
|
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"))
|
||||||
|
|
|
@ -297,11 +297,6 @@ class FormsExtraTestCase(TestCase, AssertFormErrorsMixin):
|
||||||
<option value="2013">2013</option>
|
<option value="2013">2013</option>
|
||||||
</select>""")
|
</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'})
|
a = GetDate({'mydate_month': '4', 'mydate_day': '1', 'mydate_year': '2008'})
|
||||||
self.assertTrue(a.is_valid())
|
self.assertTrue(a.is_valid())
|
||||||
self.assertEqual(a.cleaned_data['mydate'], datetime.date(2008, 4, 1))
|
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'})
|
d = GetDate({'mydate_month': '1', 'mydate_day': '1', 'mydate_year': '2010'})
|
||||||
self.assertTrue('<label for="id_mydate_month">' in d.as_p())
|
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):
|
def test_multiwidget(self):
|
||||||
# MultiWidget and MultiValueField #############################################
|
# MultiWidget and MultiValueField #############################################
|
||||||
# MultiWidgets are widgets composed of other widgets. They are usually
|
# MultiWidgets are widgets composed of other widgets. They are usually
|
||||||
|
|
Loading…
Reference in New Issue