Loading django/forms/extras/widgets.py +10 −3 Original line number Diff line number Diff line Loading @@ -51,16 +51,23 @@ class SelectDateWidget(Widget): day_field = '%s_day' year_field = '%s_year' def __init__(self, attrs=None, years=None, required=True): # years is an optional list/tuple of years to use in the "year" select box. def __init__(self, attrs=None, years=None, required=True, months=None): self.attrs = attrs or {} self.required = required # Optional list or tuple of years to use in the "year" select box. if years: self.years = years else: this_year = datetime.date.today().year self.years = range(this_year, this_year+10) # Optional dict of months to use in the "month" select box. if months: self.months = months else: self.months = MONTHS def render(self, name, value, attrs=None): try: year_val, month_val, day_val = value.year, value.month, value.day Loading @@ -80,7 +87,7 @@ class SelectDateWidget(Widget): year_val, month_val, day_val = [int(v) for v in match.groups()] choices = [(i, i) for i in self.years] year_html = self.create_select(name, self.year_field, value, year_val, choices) choices = list(six.iteritems(MONTHS)) choices = list(six.iteritems(self.months)) month_html = self.create_select(name, self.month_field, value, month_val, choices) choices = [(i, i) for i in range(1, 32)] day_html = self.create_select(name, self.day_field, value, day_val, choices) Loading docs/ref/forms/widgets.txt +17 −0 Original line number Diff line number Diff line Loading @@ -763,3 +763,20 @@ Composite widgets An optional list/tuple of years to use in the "year" select box. The default is a list containing the current year and the next 9 years. .. attribute:: SelectDateWidget.months .. versionadded:: 1.7 An optional dict of months to use in the "months" select box. The keys of the dict correspond to the month number (1-indexed) and the values are the displayed months. .. code-block:: python MONTHS = { 1:_('jan'), 2:_('feb'), 3:_('mar'), 4:_('apr'), 5:_('may'), 6:_('jun'), 7:_('jul'), 8:_('aug'), 9:_('sep'), 10:_('oct'), 11:_('nov'), 12:_('dec') } docs/releases/1.7.txt +4 −0 Original line number Diff line number Diff line Loading @@ -213,6 +213,10 @@ Forms return ``self.cleaned_data``. If it does return a changed dictionary then that will still be used. * :attr:`SelectDateWidget.months <django.forms.extras.widgets.SelectDateWidget.months>` can be used to customize the wording of the months displayed in the select widget. Management Commands ^^^^^^^^^^^^^^^^^^^ Loading tests/forms_tests/tests/test_extra.py +67 −3 Original line number Diff line number Diff line Loading @@ -10,6 +10,7 @@ from django.test import TestCase from django.test.utils import override_settings from django.utils import six from django.utils import translation from django.utils.dates import MONTHS_AP from django.utils.encoding import force_text, smart_text, python_2_unicode_compatible from .test_error_messages import AssertFormErrorsMixin Loading @@ -32,6 +33,8 @@ class FormsExtraTestCase(TestCase, AssertFormErrorsMixin): # The forms library comes with some extra, higher-level Field and Widget def test_selectdate(self): w = SelectDateWidget(years=('2007','2008','2009','2010','2011','2012','2013','2014','2015','2016')) # Rendering the default state. self.assertHTMLEqual(w.render('mydate', ''), """<select name="mydate_month" id="id_mydate_month"> <option value="0">---</option> <option value="1">January</option> Loading Loading @@ -96,8 +99,11 @@ class FormsExtraTestCase(TestCase, AssertFormErrorsMixin): <option value="2015">2015</option> <option value="2016">2016</option> </select>""") # Rendering the None or '' values should yield the same output. self.assertHTMLEqual(w.render('mydate', None), w.render('mydate', '')) # Rendering a string value. self.assertHTMLEqual(w.render('mydate', '2010-04-15'), """<select name="mydate_month" id="id_mydate_month"> <option value="1">January</option> <option value="2">February</option> Loading Loading @@ -158,10 +164,10 @@ class FormsExtraTestCase(TestCase, AssertFormErrorsMixin): <option value="2016">2016</option> </select>""") # Accepts a datetime or a string: # Rendering a datetime value. self.assertHTMLEqual(w.render('mydate', datetime.date(2010, 4, 15)), w.render('mydate', '2010-04-15')) # Invalid dates still render the failed date: # Invalid dates should still render the failed date. self.assertHTMLEqual(w.render('mydate', '2010-02-31'), """<select name="mydate_month" id="id_mydate_month"> <option value="1">January</option> <option value="2" selected="selected">February</option> Loading Loading @@ -222,7 +228,65 @@ class FormsExtraTestCase(TestCase, AssertFormErrorsMixin): <option value="2016">2016</option> </select>""") # Using a SelectDateWidget in a form: # Rendering with a custom months dict. w = SelectDateWidget(months=MONTHS_AP, years=('2013',)) self.assertHTMLEqual(w.render('mydate', ''), """<select name="mydate_month" id="id_mydate_month"> <option value="0">---</option> <option value="1">Jan.</option> <option value="2">Feb.</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">Aug.</option> <option value="9">Sept.</option> <option value="10">Oct.</option> <option value="11">Nov.</option> <option value="12">Dec.</option> </select> <select name="mydate_day" id="id_mydate_day"> <option value="0">---</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">---</option> <option value="2013">2013</option> </select>""") # Using a SelectDateWidget in a form. w = SelectDateWidget(years=('2007','2008','2009','2010','2011','2012','2013','2014','2015','2016'), required=False) self.assertHTMLEqual(w.render('mydate', ''), """<select name="mydate_month" id="id_mydate_month"> <option value="0">---</option> Loading Loading
django/forms/extras/widgets.py +10 −3 Original line number Diff line number Diff line Loading @@ -51,16 +51,23 @@ class SelectDateWidget(Widget): day_field = '%s_day' year_field = '%s_year' def __init__(self, attrs=None, years=None, required=True): # years is an optional list/tuple of years to use in the "year" select box. def __init__(self, attrs=None, years=None, required=True, months=None): self.attrs = attrs or {} self.required = required # Optional list or tuple of years to use in the "year" select box. if years: self.years = years else: this_year = datetime.date.today().year self.years = range(this_year, this_year+10) # Optional dict of months to use in the "month" select box. if months: self.months = months else: self.months = MONTHS def render(self, name, value, attrs=None): try: year_val, month_val, day_val = value.year, value.month, value.day Loading @@ -80,7 +87,7 @@ class SelectDateWidget(Widget): year_val, month_val, day_val = [int(v) for v in match.groups()] choices = [(i, i) for i in self.years] year_html = self.create_select(name, self.year_field, value, year_val, choices) choices = list(six.iteritems(MONTHS)) choices = list(six.iteritems(self.months)) month_html = self.create_select(name, self.month_field, value, month_val, choices) choices = [(i, i) for i in range(1, 32)] day_html = self.create_select(name, self.day_field, value, day_val, choices) Loading
docs/ref/forms/widgets.txt +17 −0 Original line number Diff line number Diff line Loading @@ -763,3 +763,20 @@ Composite widgets An optional list/tuple of years to use in the "year" select box. The default is a list containing the current year and the next 9 years. .. attribute:: SelectDateWidget.months .. versionadded:: 1.7 An optional dict of months to use in the "months" select box. The keys of the dict correspond to the month number (1-indexed) and the values are the displayed months. .. code-block:: python MONTHS = { 1:_('jan'), 2:_('feb'), 3:_('mar'), 4:_('apr'), 5:_('may'), 6:_('jun'), 7:_('jul'), 8:_('aug'), 9:_('sep'), 10:_('oct'), 11:_('nov'), 12:_('dec') }
docs/releases/1.7.txt +4 −0 Original line number Diff line number Diff line Loading @@ -213,6 +213,10 @@ Forms return ``self.cleaned_data``. If it does return a changed dictionary then that will still be used. * :attr:`SelectDateWidget.months <django.forms.extras.widgets.SelectDateWidget.months>` can be used to customize the wording of the months displayed in the select widget. Management Commands ^^^^^^^^^^^^^^^^^^^ Loading
tests/forms_tests/tests/test_extra.py +67 −3 Original line number Diff line number Diff line Loading @@ -10,6 +10,7 @@ from django.test import TestCase from django.test.utils import override_settings from django.utils import six from django.utils import translation from django.utils.dates import MONTHS_AP from django.utils.encoding import force_text, smart_text, python_2_unicode_compatible from .test_error_messages import AssertFormErrorsMixin Loading @@ -32,6 +33,8 @@ class FormsExtraTestCase(TestCase, AssertFormErrorsMixin): # The forms library comes with some extra, higher-level Field and Widget def test_selectdate(self): w = SelectDateWidget(years=('2007','2008','2009','2010','2011','2012','2013','2014','2015','2016')) # Rendering the default state. self.assertHTMLEqual(w.render('mydate', ''), """<select name="mydate_month" id="id_mydate_month"> <option value="0">---</option> <option value="1">January</option> Loading Loading @@ -96,8 +99,11 @@ class FormsExtraTestCase(TestCase, AssertFormErrorsMixin): <option value="2015">2015</option> <option value="2016">2016</option> </select>""") # Rendering the None or '' values should yield the same output. self.assertHTMLEqual(w.render('mydate', None), w.render('mydate', '')) # Rendering a string value. self.assertHTMLEqual(w.render('mydate', '2010-04-15'), """<select name="mydate_month" id="id_mydate_month"> <option value="1">January</option> <option value="2">February</option> Loading Loading @@ -158,10 +164,10 @@ class FormsExtraTestCase(TestCase, AssertFormErrorsMixin): <option value="2016">2016</option> </select>""") # Accepts a datetime or a string: # Rendering a datetime value. self.assertHTMLEqual(w.render('mydate', datetime.date(2010, 4, 15)), w.render('mydate', '2010-04-15')) # Invalid dates still render the failed date: # Invalid dates should still render the failed date. self.assertHTMLEqual(w.render('mydate', '2010-02-31'), """<select name="mydate_month" id="id_mydate_month"> <option value="1">January</option> <option value="2" selected="selected">February</option> Loading Loading @@ -222,7 +228,65 @@ class FormsExtraTestCase(TestCase, AssertFormErrorsMixin): <option value="2016">2016</option> </select>""") # Using a SelectDateWidget in a form: # Rendering with a custom months dict. w = SelectDateWidget(months=MONTHS_AP, years=('2013',)) self.assertHTMLEqual(w.render('mydate', ''), """<select name="mydate_month" id="id_mydate_month"> <option value="0">---</option> <option value="1">Jan.</option> <option value="2">Feb.</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">Aug.</option> <option value="9">Sept.</option> <option value="10">Oct.</option> <option value="11">Nov.</option> <option value="12">Dec.</option> </select> <select name="mydate_day" id="id_mydate_day"> <option value="0">---</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">---</option> <option value="2013">2013</option> </select>""") # Using a SelectDateWidget in a form. w = SelectDateWidget(years=('2007','2008','2009','2010','2011','2012','2013','2014','2015','2016'), required=False) self.assertHTMLEqual(w.render('mydate', ''), """<select name="mydate_month" id="id_mydate_month"> <option value="0">---</option> Loading