Ticket #6231: ticket_6231_v3.patch

File ticket_6231_v3.patch, 26.0 KB (added by Bernd Schlapsi, 7 years ago)

integrated patch for ticket #9124

  • django/forms/extras/widgets.py

     
    66import re
    77
    88from django.forms.widgets import Widget, Select
    9 from django.utils.dates import MONTHS
     9from django.utils.dates import MONTHS, MONTHS_AP, MONTHS_3
    1010from django.utils.safestring import mark_safe
     11from django.conf import settings
    1112
    12 __all__ = ('SelectDateWidget',)
     13__all__ = ('SelectDateWidget', 'SelectTimeWidget',)
    1314
    14 RE_DATE = re.compile(r'(\d{4})-(\d\d?)-(\d\d?)$')
    1515
    16 class SelectDateWidget(Widget):
     16class SelectDateWidgetBase(Widget):
    1717    """
    18     A Widget that splits date input into three <select> boxes.
     18    Base class for SelectDateWidget, SelectDateTimeWidget and
     19    SelectTimeWidget.
     20    """
     21    def __init__(self, attrs=None, format=None, required=True):
     22        if attrs is None:
     23            attrs = {}
     24        self.attrs = attrs       
     25        self.values = {}
     26        self.format = self.parse_format(format)
     27        self.required= required
    1928
    20     This also serves as an example of a Widget that has more than one HTML
    21     element and hence implements value_from_datadict.
     29    def render(self, name, value, attrs=None):
     30        """
     31        Return the html code of the widget.
     32        """
     33        if 'id' in self.attrs:
     34            id_ = self.attrs['id']
     35        else:
     36            id_ = 'id_%s' % name
     37        local_attrs = self.build_attrs()
     38        self.values = self.parse_value(value)
     39        output = []
     40        for (n, fmt) in self.format:
     41            select_name = '%s_%s' % (name, n)
     42            local_attrs['id'] = '%s_%s' % (id_, n)
     43            if hasattr(self, '%s_choices' % n):
     44                choices=getattr(self, '%s_choices' % n)(fmt)
     45                if not self.required or not self.values[n]:
     46                    choices.insert(0, (-1, '---'))
     47                select = Select(choices=choices)
     48                html = select.render(select_name, self.values[n], local_attrs)
     49                output.append(html)
     50        return mark_safe(u'\n'.join(output))
     51
     52    def id_for_label(self, id_):
     53        return '%s_%s' % (self.format[0][1], id_)
     54    id_for_label = classmethod(id_for_label)
     55
     56    def value_from_datadict(self, data, files, name):
     57        raise NotImplementedError('SelectDateWidgetBase::value_from_datadict()\
     58                is abstract and must be implemented in child classes')
     59
     60    def parse_format(self, fmt):
     61        raise NotImplementedError('SelectDateWidgetBase::parse_format() is \
     62                abstract and must be implemented in child classes')
     63
     64    def parse_value(self, fmt):
     65        raise NotImplementedError('SelectDateWidgetBase::parse_value() is \
     66                abstract and must be implemented in child classes')
     67
     68
     69class SelectDateWidget(SelectDateWidgetBase):
    2270    """
    23     month_field = '%s_month'
    24     day_field = '%s_day'
    25     year_field = '%s_year'
    26 
    27     def __init__(self, attrs=None, years=None):
     71    A Widget that splits date input into three <select> boxes.
     72    """
     73    def __init__(self, attrs=None, years=None, format=None, required=True):
    2874        # years is an optional list/tuple of years to use in the "year" select box.
    29         self.attrs = attrs or {}
    3075        if years:
    3176            self.years = years
    3277        else:
    3378            this_year = datetime.date.today().year
    3479            self.years = range(this_year, this_year+10)
     80        super(SelectDateWidget, self).__init__(attrs, format, required)
    3581
    36     def render(self, name, value, attrs=None):
    37         try:
    38             year_val, month_val, day_val = value.year, value.month, value.day
    39         except AttributeError:
    40             year_val = month_val = day_val = None
    41             if isinstance(value, basestring):
    42                 match = RE_DATE.match(value)
    43                 if match:
    44                     year_val, month_val, day_val = [int(v) for v in match.groups()]
     82    def value_from_datadict(self, data, files, name):
     83        vals = []
     84        y = data.get('%s_year' % name)
     85        m = data.get('%s_month' % name)
     86        d = data.get('%s_day' % name)
     87        if y == m == d == '-1':
     88            return None
     89        if y and m and d:
     90            return u'-'.join([y, m, d])
     91        return data.get(name, None)
    4592
    46         output = []
    47 
    48         if 'id' in self.attrs:
    49             id_ = self.attrs['id']
     93    def parse_value(self, val):
     94        ret = {}
     95        if isinstance(val, datetime.date):
     96            ret['month'] = val.month
     97            ret['day'] = val.day
     98            ret['year'] = val.year
    5099        else:
    51             id_ = 'id_%s' % name
     100            try:
     101                l = map(int, val.split('-'))
     102            except (ValueError, AttributeError):
     103                l = (None, None, None)
     104            for i, k in [(0, 'year'), (1, 'month'), (2, 'day')]:
     105                try:
     106                    ret[k] = l[i]
     107                except IndexError:
     108                    ret[k] = None
     109        return ret
    52110
    53         month_choices = MONTHS.items()
    54         month_choices.sort()
    55         local_attrs = self.build_attrs(id=self.month_field % id_)
    56         select_html = Select(choices=month_choices).render(self.month_field % name, month_val, local_attrs)
    57         output.append(select_html)
     111    def parse_format(self, fmt):
     112        """
     113        Parse the given format `fmt` and set the format property.
     114        """
     115        if fmt is None:
     116            fmt = settings.DATE_FORMAT
     117        ret = []
     118        for item in fmt:
     119            if item in ['d', 'D', 'j', 'L']:
     120                ret.append(('day', item,))
     121            elif item in ['n', 'm', 'F', 'b', 'M', 'N']:
     122                ret.append(('month', item,))
     123            elif item in ['y', 'Y']:
     124                ret.append(('year', item,))
     125        return ret
    58126
    59         day_choices = [(i, i) for i in range(1, 32)]
    60         local_attrs['id'] = self.day_field % id_
    61         select_html = Select(choices=day_choices).render(self.day_field % name, day_val, local_attrs)
    62         output.append(select_html)
     127    def month_choices(self, fmt):
     128        """
     129        Return list of choices (tuple (key, value)) for monthes select.
     130        """
     131        if fmt == 'n':
     132            # month numbers without leading 0 (1 .. 12)
     133            return [(i, i) for i in range(1, 13)]
     134        elif fmt == 'm':
     135            # month numbers with leading 0 (01 .. 12)
     136            return [(i, '%02d' % i) for i in range(1, 13)]
     137        elif fmt in ['F', 'b', 'M', 'N']:
     138            if fmt == 'F':
     139                # full month names
     140                month_choices = MONTHS.items()
     141            elif fmt == 'b':
     142                # 3 first letters of month lowercase
     143                month_choices = [(k, v.lower()) for (k, v) in MONTHS_3.items()]
     144            elif fmt == 'M':
     145                # 3 first letters of month
     146                month_choices = MONTHS_3.items()
     147            elif fmt == 'N':
     148                # abbrev of month names
     149                month_choices = MONTHS_AP.items()
     150            month_choices.sort()
     151            return month_choices
     152        return []
    63153
    64         year_choices = [(i, i) for i in self.years]
    65         local_attrs['id'] = self.year_field % id_
    66         select_html = Select(choices=year_choices).render(self.year_field % name, year_val, local_attrs)
    67         output.append(select_html)
     154    def day_choices(self, fmt):
     155        """
     156        Return list of choices (tuple (key, value)) for days select.
     157        """
     158        if fmt == 'j':
     159            # day of month number without leading 0
     160            return [(i, i) for i in range(1, 32)]
     161        elif fmt == 'd':
     162            # day of month number with leading 0
     163            return [(i, '%02d' % i) for i in range(1, 32)]
     164        return []
    68165
    69         return mark_safe(u'\n'.join(output))
     166    def year_choices(self, fmt):
     167        """
     168        Return list of choices (tuple (key, value)) for years select.
     169        """
     170        if fmt == 'Y':
     171            # years with 4 numbers
     172            return [(i, i) for i in self.years]
     173        elif fmt == 'y':
     174            # years with only the last 2 numbers
     175            return [(i, str(i)[-2:]) for i in self.years]
     176        return []
    70177
    71     def id_for_label(self, id_):
    72         return '%s_month' % id_
    73     id_for_label = classmethod(id_for_label)
    74178
     179class SelectTimeWidget(SelectDateWidgetBase):
     180    """
     181    A Widget that splits time input into two or three <select> boxes.
     182    XXX: at the moment it is limited to theses formats: 'Hi' and 'His'.
     183    """
     184    def __init__(self, attrs=None, format=None, required=True):
     185        super(SelectTimeWidget, self).__init__(attrs, format, required)
     186
     187    def parse_format(self, fmt):
     188        if fmt not in ['Hi', 'His']:
     189            fmt = 'Hi'
     190        ret = []
     191        for item in fmt:
     192            if item == 'H':
     193                ret.append(('hour', item,))
     194            elif item == 'i':
     195                ret.append(('minute', item,))
     196            elif item == 's':
     197                ret.append(('second', item,))
     198        return ret
     199
     200    def parse_value(self, val):
     201        ret = {}
     202        if isinstance(val, datetime.time):
     203            ret['hour'] = val.hour
     204            ret['minute'] = val.minute
     205            ret['second'] = val.second
     206        else:
     207            try:
     208                l = map(int, val.split(':'))
     209            except (ValueError, AttributeError):
     210                l = (None, None, None)
     211            for i, k in [(0, 'hour'), (1, 'minute'), (2, 'second')]:
     212                try:
     213                    ret[k] = l[i]
     214                except IndexError:
     215                    ret[k] = None
     216        return ret
     217
    75218    def value_from_datadict(self, data, files, name):
    76         y, m, d = data.get(self.year_field % name), data.get(self.month_field % name), data.get(self.day_field % name)
    77         if y and m and d:
    78             return '%s-%s-%s' % (y, m, d)
     219        vals = []
     220        h = data.get('%s_hour' % name)
     221        m = data.get('%s_minute' % name)
     222        s = data.get('%s_second' % name)
     223        if h and m:
     224            if s:
     225                return u':'.join([h, m, s])
     226            else:
     227                return u':'.join([h, m])
    79228        return data.get(name, None)
     229
     230    def hour_choices(self, fmt):
     231        """
     232        Return list of choices (tuple (key, value)) for hours select.
     233        """
     234        # hour 24H format with leading 0
     235        return [(i, '%02d' % i) for i in range(0, 24)]
     236
     237    def minute_choices(self, fmt):
     238        """
     239        Return list of choices (tuple (key, value)) for minutes select.
     240        """
     241        # minutes with leading 0
     242        return [(i, '%02d' % i) for i in range(0, 60)]
     243
     244    def second_choices(self, fmt):
     245        """
     246        Return list of choices (tuple (key, value)) for seconds select.
     247        """
     248        # seconds with leading 0
     249        return [(i, '%02d' % i) for i in range(0, 60)]
     250
  • tests/regressiontests/forms/extra.py

     
    2020# SelectDateWidget ############################################################
    2121
    2222>>> from django.forms.extras import SelectDateWidget
    23 >>> w = SelectDateWidget(years=('2007','2008','2009','2010','2011','2012','2013','2014','2015','2016'))
     23>>> w = SelectDateWidget(years=('2007','2008','2009','2010','2011','2012','2013','2014','2015','2016'), format='FjY')
    2424>>> print w.render('mydate', '')
    2525<select name="mydate_month" id="id_mydate_month">
     26<option value="-1">---</option>
    2627<option value="1">January</option>
    2728<option value="2">February</option>
    2829<option value="3">March</option>
     
    3738<option value="12">December</option>
    3839</select>
    3940<select name="mydate_day" id="id_mydate_day">
     41<option value="-1">---</option>
    4042<option value="1">1</option>
    4143<option value="2">2</option>
    4244<option value="3">3</option>
     
    7072<option value="31">31</option>
    7173</select>
    7274<select name="mydate_year" id="id_mydate_year">
     75<option value="-1">---</option>
    7376<option value="2007">2007</option>
    7477<option value="2008">2008</option>
    7578<option value="2009">2009</option>
     
    233236>>> print b.cleaned_data['mydate']
    2342372008-04-01
    235238
     239>>> w = SelectDateWidget(years=('2007','2008','2009','2010','2011','2012','2013','2014','2015','2016'), required=False)
     240>>> print w.render('mydate', '')
     241<select name="mydate_month" id="id_mydate_month">
     242<option value="-1">---</option>
     243<option value="1">Jan.</option>
     244<option value="2">Feb.</option>
     245<option value="3">March</option>
     246<option value="4">April</option>
     247<option value="5">May</option>
     248<option value="6">June</option>
     249<option value="7">July</option>
     250<option value="8">Aug.</option>
     251<option value="9">Sept.</option>
     252<option value="10">Oct.</option>
     253<option value="11">Nov.</option>
     254<option value="12">Dec.</option>
     255</select>
     256<select name="mydate_day" id="id_mydate_day">
     257<option value="-1">---</option>
     258<option value="1">1</option>
     259<option value="2">2</option>
     260<option value="3">3</option>
     261<option value="4">4</option>
     262<option value="5">5</option>
     263<option value="6">6</option>
     264<option value="7">7</option>
     265<option value="8">8</option>
     266<option value="9">9</option>
     267<option value="10">10</option>
     268<option value="11">11</option>
     269<option value="12">12</option>
     270<option value="13">13</option>
     271<option value="14">14</option>
     272<option value="15">15</option>
     273<option value="16">16</option>
     274<option value="17">17</option>
     275<option value="18">18</option>
     276<option value="19">19</option>
     277<option value="20">20</option>
     278<option value="21">21</option>
     279<option value="22">22</option>
     280<option value="23">23</option>
     281<option value="24">24</option>
     282<option value="25">25</option>
     283<option value="26">26</option>
     284<option value="27">27</option>
     285<option value="28">28</option>
     286<option value="29">29</option>
     287<option value="30">30</option>
     288<option value="31">31</option>
     289</select>
     290<select name="mydate_year" id="id_mydate_year">
     291<option value="-1">---</option>
     292<option value="2007">2007</option>
     293<option value="2008">2008</option>
     294<option value="2009">2009</option>
     295<option value="2010">2010</option>
     296<option value="2011">2011</option>
     297<option value="2012">2012</option>
     298<option value="2013">2013</option>
     299<option value="2014">2014</option>
     300<option value="2015">2015</option>
     301<option value="2016">2016</option>
     302</select>
     303>>> print w.render('mydate', '2010-04-15')
     304<select name="mydate_month" id="id_mydate_month">
     305<option value="-1">---</option>
     306<option value="1">Jan.</option>
     307<option value="2">Feb.</option>
     308<option value="3">March</option>
     309<option value="4" selected="selected">April</option>
     310<option value="5">May</option>
     311<option value="6">June</option>
     312<option value="7">July</option>
     313<option value="8">Aug.</option>
     314<option value="9">Sept.</option>
     315<option value="10">Oct.</option>
     316<option value="11">Nov.</option>
     317<option value="12">Dec.</option>
     318</select>
     319<select name="mydate_day" id="id_mydate_day">
     320<option value="-1">---</option>
     321<option value="1">1</option>
     322<option value="2">2</option>
     323<option value="3">3</option>
     324<option value="4">4</option>
     325<option value="5">5</option>
     326<option value="6">6</option>
     327<option value="7">7</option>
     328<option value="8">8</option>
     329<option value="9">9</option>
     330<option value="10">10</option>
     331<option value="11">11</option>
     332<option value="12">12</option>
     333<option value="13">13</option>
     334<option value="14">14</option>
     335<option value="15" selected="selected">15</option>
     336<option value="16">16</option>
     337<option value="17">17</option>
     338<option value="18">18</option>
     339<option value="19">19</option>
     340<option value="20">20</option>
     341<option value="21">21</option>
     342<option value="22">22</option>
     343<option value="23">23</option>
     344<option value="24">24</option>
     345<option value="25">25</option>
     346<option value="26">26</option>
     347<option value="27">27</option>
     348<option value="28">28</option>
     349<option value="29">29</option>
     350<option value="30">30</option>
     351<option value="31">31</option>
     352</select>
     353<select name="mydate_year" id="id_mydate_year">
     354<option value="-1">---</option>
     355<option value="2007">2007</option>
     356<option value="2008">2008</option>
     357<option value="2009">2009</option>
     358<option value="2010" selected="selected">2010</option>
     359<option value="2011">2011</option>
     360<option value="2012">2012</option>
     361<option value="2013">2013</option>
     362<option value="2014">2014</option>
     363<option value="2015">2015</option>
     364<option value="2016">2016</option>
     365</select>
    236366
     367
     368# SelectTimeWidget ############################################################
     369
     370>>> from django.forms.extras import SelectTimeWidget
     371>>> w = SelectTimeWidget()
     372>>> print w.render('mytime', '')
     373<select name="mytime_hour" id="id_mytime_hour">
     374<option value="-1">---</option>
     375<option value="0">00</option>
     376<option value="1">01</option>
     377<option value="2">02</option>
     378<option value="3">03</option>
     379<option value="4">04</option>
     380<option value="5">05</option>
     381<option value="6">06</option>
     382<option value="7">07</option>
     383<option value="8">08</option>
     384<option value="9">09</option>
     385<option value="10">10</option>
     386<option value="11">11</option>
     387<option value="12">12</option>
     388<option value="13">13</option>
     389<option value="14">14</option>
     390<option value="15">15</option>
     391<option value="16">16</option>
     392<option value="17">17</option>
     393<option value="18">18</option>
     394<option value="19">19</option>
     395<option value="20">20</option>
     396<option value="21">21</option>
     397<option value="22">22</option>
     398<option value="23">23</option>
     399</select>
     400<select name="mytime_minute" id="id_mytime_minute">
     401<option value="-1">---</option>
     402<option value="0">00</option>
     403<option value="1">01</option>
     404<option value="2">02</option>
     405<option value="3">03</option>
     406<option value="4">04</option>
     407<option value="5">05</option>
     408<option value="6">06</option>
     409<option value="7">07</option>
     410<option value="8">08</option>
     411<option value="9">09</option>
     412<option value="10">10</option>
     413<option value="11">11</option>
     414<option value="12">12</option>
     415<option value="13">13</option>
     416<option value="14">14</option>
     417<option value="15">15</option>
     418<option value="16">16</option>
     419<option value="17">17</option>
     420<option value="18">18</option>
     421<option value="19">19</option>
     422<option value="20">20</option>
     423<option value="21">21</option>
     424<option value="22">22</option>
     425<option value="23">23</option>
     426<option value="24">24</option>
     427<option value="25">25</option>
     428<option value="26">26</option>
     429<option value="27">27</option>
     430<option value="28">28</option>
     431<option value="29">29</option>
     432<option value="30">30</option>
     433<option value="31">31</option>
     434<option value="32">32</option>
     435<option value="33">33</option>
     436<option value="34">34</option>
     437<option value="35">35</option>
     438<option value="36">36</option>
     439<option value="37">37</option>
     440<option value="38">38</option>
     441<option value="39">39</option>
     442<option value="40">40</option>
     443<option value="41">41</option>
     444<option value="42">42</option>
     445<option value="43">43</option>
     446<option value="44">44</option>
     447<option value="45">45</option>
     448<option value="46">46</option>
     449<option value="47">47</option>
     450<option value="48">48</option>
     451<option value="49">49</option>
     452<option value="50">50</option>
     453<option value="51">51</option>
     454<option value="52">52</option>
     455<option value="53">53</option>
     456<option value="54">54</option>
     457<option value="55">55</option>
     458<option value="56">56</option>
     459<option value="57">57</option>
     460<option value="58">58</option>
     461<option value="59">59</option>
     462</select>
     463>>> w = SelectTimeWidget(required=False)
     464>>> print w.render('mytime', '15:45')
     465<select name="mytime_hour" id="id_mytime_hour">
     466<option value="-1">---</option>
     467<option value="0">00</option>
     468<option value="1">01</option>
     469<option value="2">02</option>
     470<option value="3">03</option>
     471<option value="4">04</option>
     472<option value="5">05</option>
     473<option value="6">06</option>
     474<option value="7">07</option>
     475<option value="8">08</option>
     476<option value="9">09</option>
     477<option value="10">10</option>
     478<option value="11">11</option>
     479<option value="12">12</option>
     480<option value="13">13</option>
     481<option value="14">14</option>
     482<option value="15" selected="selected">15</option>
     483<option value="16">16</option>
     484<option value="17">17</option>
     485<option value="18">18</option>
     486<option value="19">19</option>
     487<option value="20">20</option>
     488<option value="21">21</option>
     489<option value="22">22</option>
     490<option value="23">23</option>
     491</select>
     492<select name="mytime_minute" id="id_mytime_minute">
     493<option value="-1">---</option>
     494<option value="0">00</option>
     495<option value="1">01</option>
     496<option value="2">02</option>
     497<option value="3">03</option>
     498<option value="4">04</option>
     499<option value="5">05</option>
     500<option value="6">06</option>
     501<option value="7">07</option>
     502<option value="8">08</option>
     503<option value="9">09</option>
     504<option value="10">10</option>
     505<option value="11">11</option>
     506<option value="12">12</option>
     507<option value="13">13</option>
     508<option value="14">14</option>
     509<option value="15">15</option>
     510<option value="16">16</option>
     511<option value="17">17</option>
     512<option value="18">18</option>
     513<option value="19">19</option>
     514<option value="20">20</option>
     515<option value="21">21</option>
     516<option value="22">22</option>
     517<option value="23">23</option>
     518<option value="24">24</option>
     519<option value="25">25</option>
     520<option value="26">26</option>
     521<option value="27">27</option>
     522<option value="28">28</option>
     523<option value="29">29</option>
     524<option value="30">30</option>
     525<option value="31">31</option>
     526<option value="32">32</option>
     527<option value="33">33</option>
     528<option value="34">34</option>
     529<option value="35">35</option>
     530<option value="36">36</option>
     531<option value="37">37</option>
     532<option value="38">38</option>
     533<option value="39">39</option>
     534<option value="40">40</option>
     535<option value="41">41</option>
     536<option value="42">42</option>
     537<option value="43">43</option>
     538<option value="44">44</option>
     539<option value="45" selected="selected">45</option>
     540<option value="46">46</option>
     541<option value="47">47</option>
     542<option value="48">48</option>
     543<option value="49">49</option>
     544<option value="50">50</option>
     545<option value="51">51</option>
     546<option value="52">52</option>
     547<option value="53">53</option>
     548<option value="54">54</option>
     549<option value="55">55</option>
     550<option value="56">56</option>
     551<option value="57">57</option>
     552<option value="58">58</option>
     553<option value="59">59</option>
     554</select>
     555>>> w = SelectTimeWidget(required=True)
     556>>> print w.render('mytime', '15:45')
     557<select name="mytime_hour" id="id_mytime_hour">
     558<option value="0">00</option>
     559<option value="1">01</option>
     560<option value="2">02</option>
     561<option value="3">03</option>
     562<option value="4">04</option>
     563<option value="5">05</option>
     564<option value="6">06</option>
     565<option value="7">07</option>
     566<option value="8">08</option>
     567<option value="9">09</option>
     568<option value="10">10</option>
     569<option value="11">11</option>
     570<option value="12">12</option>
     571<option value="13">13</option>
     572<option value="14">14</option>
     573<option value="15" selected="selected">15</option>
     574<option value="16">16</option>
     575<option value="17">17</option>
     576<option value="18">18</option>
     577<option value="19">19</option>
     578<option value="20">20</option>
     579<option value="21">21</option>
     580<option value="22">22</option>
     581<option value="23">23</option>
     582</select>
     583<select name="mytime_minute" id="id_mytime_minute">
     584<option value="0">00</option>
     585<option value="1">01</option>
     586<option value="2">02</option>
     587<option value="3">03</option>
     588<option value="4">04</option>
     589<option value="5">05</option>
     590<option value="6">06</option>
     591<option value="7">07</option>
     592<option value="8">08</option>
     593<option value="9">09</option>
     594<option value="10">10</option>
     595<option value="11">11</option>
     596<option value="12">12</option>
     597<option value="13">13</option>
     598<option value="14">14</option>
     599<option value="15">15</option>
     600<option value="16">16</option>
     601<option value="17">17</option>
     602<option value="18">18</option>
     603<option value="19">19</option>
     604<option value="20">20</option>
     605<option value="21">21</option>
     606<option value="22">22</option>
     607<option value="23">23</option>
     608<option value="24">24</option>
     609<option value="25">25</option>
     610<option value="26">26</option>
     611<option value="27">27</option>
     612<option value="28">28</option>
     613<option value="29">29</option>
     614<option value="30">30</option>
     615<option value="31">31</option>
     616<option value="32">32</option>
     617<option value="33">33</option>
     618<option value="34">34</option>
     619<option value="35">35</option>
     620<option value="36">36</option>
     621<option value="37">37</option>
     622<option value="38">38</option>
     623<option value="39">39</option>
     624<option value="40">40</option>
     625<option value="41">41</option>
     626<option value="42">42</option>
     627<option value="43">43</option>
     628<option value="44">44</option>
     629<option value="45" selected="selected">45</option>
     630<option value="46">46</option>
     631<option value="47">47</option>
     632<option value="48">48</option>
     633<option value="49">49</option>
     634<option value="50">50</option>
     635<option value="51">51</option>
     636<option value="52">52</option>
     637<option value="53">53</option>
     638<option value="54">54</option>
     639<option value="55">55</option>
     640<option value="56">56</option>
     641<option value="57">57</option>
     642<option value="58">58</option>
     643<option value="59">59</option>
     644</select>
     645
     646Accepts a datetime or a string:
     647
     648>>> w.render('mydate', datetime.time(15, 45, 15)) == w.render('mydate', '15:45:15')
     649True
     650
     651Using a SelectDateWidget in a form:
     652
     653>>> class GetTime(Form):
     654...     mytime = TimeField(widget=SelectTimeWidget)
     655>>> a = GetTime({'mytime_hour':'15', 'mytime_minute':'45', 'mytime_second':'15'})
     656>>> print a.is_valid()
     657True
     658>>> print a.cleaned_data['mytime']
     65915:45:15
     660
     661As with any widget that implements get_value_from_datadict,
     662we must be prepared to accept the input from the "as_hidden"
     663rendering as well.
     664
     665>>> print a['mytime'].as_hidden()
     666<input type="hidden" name="mytime" value="15:45:15" id="id_mytime" />
     667>>> b=GetTime({'mytime':'15:45:15'})
     668>>> print b.is_valid()
     669True
     670>>> print b.cleaned_data['mytime']
     67115:45:15
     672
     673
    237674# MultiWidget and MultiValueField #############################################
    238675# MultiWidgets are widgets composed of other widgets. They are usually
    239676# combined with MultiValueFields - a field that is composed of other fields.
Back to Top