Sealyu

          --- 博客已遷移至: http://www.sealyu.com/blog

            BlogJava :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理 ::
            618 隨筆 :: 87 文章 :: 225 評論 :: 0 Trackbacks

          This snippet defines a Widget that is very similar to the SelectDateWidget located in django.forms.extras.widgets. The main difference however is that it works with Times instead of Dates.

          The SelectTimeWidget supports both 24-hr and 12-hr formats, and flexible time increments for hours, minutes and seconds. Sample usage is illustrated below:

          # Specify a basic 24-hr time Widget (the default)
          t = forms.TimeField(widget=SelectTimeWidget())

          # Force minutes and seconds to be displayed in increments of 10
          t = forms.TimeField(widget=SelectTimeWidget(minute_step=10, second_step=10))

          # Use a 12-hr time format, which will display a 4th select
          # element containing a.m. and p.m. options)
          t = forms.TimeField(widget=SelectTimeWidget(twelve_hr=True))

          UPDATE: Changed the time pattern to a more precise regular expression, and added the sample usage above.


          import re
          from django.forms.widgets import Widget, Select, MultiWidget
          from django.forms.extras.widgets import SelectDateWidget
          from django.utils.safestring import mark_safe

          # Attempt to match many time formats:
          #
           Example: "12:34:56 P.M."  matches:
          #
           ('12', '34', ':56', '56', 'P.M.', 'P', '.', 'M', '.')
          #
           ('12', '34', ':56', '56', 'P.M.')
          #
           Note that the colon ":" before seconds is optional, but only if seconds are omitted
          #
          time_pattern = r'(\d\d?):(\d\d)(:(\d\d))? *((a{1}|A{1}|p{1}|P{1})(\.)?(m{1}|M{1})(\.)?)?$'
          time_pattern = r'(\d\d?):(\d\d)(:(\d\d))? *([aApP]\.?[mM]\.?)?$' # w/ Magus's suggestions

          RE_TIME 
          = re.compile(time_pattern)
          # The following are just more readable ways to access re.matched groups:
          HOURS = 0
          MINUTES 
          = 1
          SECONDS 
          = 3
          MERIDIEM 
          = 4

          class SelectTimeWidget(Widget):
              
          """
              A Widget that splits time input into <select> elements.
              Allows form to show as 24hr: <hour>:<minute>:<second>,
              or as 12hr: <hour>:<minute>:<second> <am|pm> 
              
              Also allows user-defined increments for minutes/seconds
              
          """
              hour_field 
          = '%s_hour'
              minute_field 
          = '%s_minute'
              second_field 
          = '%s_second' 
              meridiem_field 
          = '%s_meridiem'
              twelve_hr 
          = False # Default to 24hr.
              
              
          def __init__(self, attrs=None, hour_step=None, minute_step=None, second_step=None, twelve_hr=False):
                  
          '''
                  hour_step, minute_step, second_step are optional step values for
                  for the range of values for the associated select element
                  twelve_hr: If True, forces the output to be in 12-hr format (rather than 24-hr)
                  
          '''
                  self.attrs 
          = attrs or {}
                  
                  
          if twelve_hr:
                      self.twelve_hr 
          = True # Do 12hr (rather than 24hr)
                      self.meridiem_val = 'a.m.' # Default to Morning (A.M.)
                  
                  
          if hour_step and twelve_hr:
                      self.hours 
          = range(1,13,hour_step) 
                  
          elif hour_step: # 24hr, with stepping.
                      self.hours = range(0,24,hour_step)
                  
          elif twelve_hr: # 12hr, no stepping
                      self.hours = range(1,13)
                  
          else# 24hr, no stepping
                      self.hours = range(0,24

                  
          if minute_step:
                      self.minutes 
          = range(0,60,minute_step)
                  
          else:
                      self.minutes 
          = range(0,60)

                  
          if second_step:
                      self.seconds 
          = range(0,60,second_step)
                  
          else:
                      self.seconds 
          = range(0,60)

              
          def render(self, name, value, attrs=None):
                  
          try# try to get time values from a datetime.time object (value)
                      hour_val, minute_val, second_val = value.hour, value.minute, value.second
                      
          if self.twelve_hr:
                          
          if hour_val >= 12:
                              self.meridiem_val 
          = 'p.m.'
                          
          else:
                              self.meridiem_val 
          = 'a.m.'
                  
          except AttributeError:
                      hour_val 
          = minute_val = second_val = 0
                      
          if isinstance(value, basestring):
                          match 
          = RE_TIME.match(value)
                          
          if match:
                              time_groups 
          = match.groups();
                              hour_val 
          = int(time_groups[HOURS]) % 24 # force to range(0-24)
                              minute_val = int(time_groups[MINUTES]) 
                              
          if time_groups[SECONDS] is None:
                                  second_val 
          = 0
                              
          else:
                                  second_val 
          = int(time_groups[SECONDS])
                              
                              
          # check to see if meridiem was passed in
                              if time_groups[MERIDIEM] is not None:
                                  self.meridiem_val 
          = time_groups[MERIDIEM]
                              
          else# otherwise, set the meridiem based on the time
                                  if self.twelve_hr:
                                      
          if hour_val >= 12:
                                          self.meridiem_val 
          = 'p.m.'
                                      
          else:
                                          self.meridiem_val 
          = 'a.m.'
                                  
          else:
                                      self.meridiem_val 
          = None
                              

                  
          # If we're doing a 12-hr clock, there will be a meridiem value, so make sure the
                  # hours get printed correctly
                  if self.twelve_hr and self.meridiem_val:
                      
          if self.meridiem_val.lower().startswith('p'and hour_val > 12 and hour_val < 24:
                          hour_val 
          = hour_val % 12
                  
          elif hour_val == 0:
                      hour_val 
          = 12
                      
                  output 
          = []
                  
          if 'id' in self.attrs:
                      id_ 
          = self.attrs['id']
                  
          else:
                      id_ 
          = 'id_%s' % name

                  
          # NOTE: for times to get displayed correctly, the values MUST be converted to unicode
                  # When Select builds a list of options, it checks against Unicode values
                  hour_val = u"%.2d" % hour_val
                  minute_val 
          = u"%.2d" % minute_val
                  second_val 
          = u"%.2d" % second_val

                  hour_choices 
          = [("%.2d"%i, "%.2d"%i) for i in self.hours]
                  local_attrs 
          = self.build_attrs(id=self.hour_field % id_)
                  select_html 
          = Select(choices=hour_choices).render(self.hour_field % name, hour_val, local_attrs)
                  output.append(select_html)

                  minute_choices 
          = [("%.2d"%i, "%.2d"%i) for i in self.minutes]
                  local_attrs[
          'id'= self.minute_field % id_
                  select_html 
          = Select(choices=minute_choices).render(self.minute_field % name, minute_val, local_attrs)
                  output.append(select_html)

                  second_choices 
          = [("%.2d"%i, "%.2d"%i) for i in self.seconds]
                  local_attrs[
          'id'= self.second_field % id_
                  select_html 
          = Select(choices=second_choices).render(self.second_field % name, second_val, local_attrs)
                  output.append(select_html)
              
                  
          if self.twelve_hr:
                      
          #  If we were given an initial value, make sure the correct meridiem get's selected.
                      if self.meridiem_val is not None and  self.meridiem_val.startswith('p'):
                              meridiem_choices 
          = [('p.m.','p.m.'), ('a.m.','a.m.')]
                      
          else:
                          meridiem_choices 
          = [('a.m.','a.m.'), ('p.m.','p.m.')]

                      local_attrs[
          'id'= local_attrs['id'= self.meridiem_field % id_
                      select_html 
          = Select(choices=meridiem_choices).render(self.meridiem_field % name, self.meridiem_val, local_attrs)
                      output.append(select_html)

                  
          return mark_safe(u'\n'.join(output))

              
          def id_for_label(self, id_):
                  
          return '%s_hour' % id_
              id_for_label 
          = classmethod(id_for_label)

              
          def value_from_datadict(self, data, files, name):
                  
          # if there's not h:m:s data, assume zero:
                  h = data.get(self.hour_field % name, 0) # hour
                  m = data.get(self.minute_field % name, 0) # minute 
                  s = data.get(self.second_field % name, 0) # second

                  meridiem 
          = data.get(self.meridiem_field % name, None)

                  
          #NOTE: if meridiem IS None, assume 24-hr
                  if meridiem is not None:
                      
          if meridiem.lower().startswith('p'and int(h) != 12:
                          h 
          = (int(h)+12)%24 
                      
          elif meridiem.lower().startswith('a'and int(h) == 12:
                          h 
          = 0
                  
                  
          if (int(h) == 0 or h) and m and s:
                      
          return '%s:%s:%s' % (h, m, s)

                  
          return data.get(name, None)
          posted on 2009-09-28 08:54 seal 閱讀(1366) 評論(0)  編輯  收藏 所屬分類: Python
          主站蜘蛛池模板: 鄯善县| 运城市| 三亚市| 都江堰市| 盱眙县| 上犹县| 宁强县| 青浦区| 林西县| 柘荣县| 旬邑县| 淮滨县| 横山县| 洛扎县| 奇台县| 丘北县| 元阳县| 巫溪县| 德昌县| 安徽省| 大关县| 丘北县| 青阳县| 苗栗县| 克拉玛依市| 丰都县| 揭阳市| 长治县| 班戈县| 梁山县| 东乌珠穆沁旗| 中卫市| 新乡县| 沙洋县| 萨迦县| 晋州市| 嘉荫县| 马鞍山市| 监利县| 汕头市| 北海市|