Advertisement
Guest User

widgets.py

a guest
Jan 31st, 2015
170
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 7.07 KB | None | 0 0
  1. import re
  2. from django.forms.extras.widgets import SelectDateWidget
  3. from django.forms.widgets import Widget, Select, MultiWidget
  4. from django.utils.safestring import mark_safe
  5.  
  6. '''
  7.    Credit: https://bradmontgomery.net/blog/selecttimewidget-a-custom-django-widget/
  8. '''
  9.  
  10.  
  11. __all__ = ('SelectTimeWidget', 'SplitSelectDateTimeWidget')
  12.  
  13. # Attempt to match many time formats:
  14. # Example: "12:34:56 P.M."  matches:
  15. # ('12', '34', ':56', '56', 'P.M.', 'P', '.', 'M', '.')
  16. # ('12', '34', ':56', '56', 'P.M.')
  17. # Note that the colon ":" before seconds is optional, but only if seconds are omitted
  18. time_pattern = r'(\d\d?):(\d\d)(:(\d\d))? *([aApP]\.?[mM]\.?)?$'
  19.  
  20. RE_TIME = re.compile(time_pattern)
  21. # The following are just more readable ways to access re.matched groups:
  22. HOURS = 0
  23. MINUTES = 1
  24. SECONDS = 3
  25. MERIDIEM = 4
  26.  
  27. class SelectTimeWidget(Widget):
  28.     """
  29.    A Widget that splits time input into <select> elements.
  30.    Allows form to show as 24hr: <hour>:<minute>:<second>, (default)
  31.    or as 12hr: <hour>:<minute>:<second> <am|pm>
  32.  
  33.    Also allows user-defined increments for minutes/seconds
  34.    """
  35.     hour_field = '%s_hour'
  36.     minute_field = '%s_minute'
  37.     #second_field = '%s_second'
  38.     meridiem_field = '%s_meridiem'
  39.     twelve_hr = False # Default to 24hr.
  40.  
  41.     def __init__(self, attrs=None, hour_step=None, minute_step=None, second_step=None, twelve_hr=False):
  42.         """
  43.        hour_step, minute_step, second_step are optional step values for
  44.        for the range of values for the associated select element
  45.        twelve_hr: If True, forces the output to be in 12-hr format (rather than 24-hr)
  46.        """
  47.         self.attrs = attrs or {}
  48.  
  49.         if twelve_hr:
  50.             self.twelve_hr = True # Do 12hr (rather than 24hr)
  51.             self.meridiem_val = 'a.m.' # Default to Morning (A.M.)
  52.  
  53.         if hour_step and twelve_hr:
  54.             self.hours = range(1,13,hour_step)
  55.         elif hour_step: # 24hr, with stepping.
  56.             self.hours = range(0,24,hour_step)
  57.         elif twelve_hr: # 12hr, no stepping
  58.             self.hours = range(1,13)
  59.         else: # 24hr, no stepping
  60.             self.hours = range(0,24)
  61.  
  62.         if minute_step:
  63.             self.minutes = range(0,60,minute_step)
  64.         else:
  65.             self.minutes = range(0,60)
  66.  
  67.         #if second_step:
  68.         #    self.seconds = range(0,60,second_step)
  69.         #else:
  70.         #    self.seconds = range(0,60)
  71.  
  72.     def render(self, name, value, attrs=None):
  73.         try: # try to get time values from a datetime.time object (value)
  74.             hour_val, minute_val, second_val = value.hour, value.minute, value.second
  75.             if self.twelve_hr:
  76.                 if hour_val >= 12:
  77.                     self.meridiem_val = 'p.m.'
  78.                 else:
  79.                     self.meridiem_val = 'a.m.'
  80.         except AttributeError:
  81.             hour_val = minute_val = second_val = 0
  82.             if isinstance(value, basestring):
  83.                 match = RE_TIME.match(value)
  84.                 if match:
  85.                     time_groups = match.groups();
  86.                     hour_val = int(time_groups[HOURS]) % 24 # force to range(0-24)
  87.                     minute_val = int(time_groups[MINUTES])
  88.                     if time_groups[SECONDS] is None:
  89.                         second_val = 0
  90.                     else:
  91.                         second_val = int(time_groups[SECONDS])
  92.  
  93.                     # check to see if meridiem was passed in
  94.                     if time_groups[MERIDIEM] is not None:
  95.                         self.meridiem_val = time_groups[MERIDIEM]
  96.                     else: # otherwise, set the meridiem based on the time
  97.                         if self.twelve_hr:
  98.                             if hour_val >= 12:
  99.                                 self.meridiem_val = 'p.m.'
  100.                             else:
  101.                                 self.meridiem_val = 'a.m.'
  102.                         else:
  103.                             self.meridiem_val = None
  104.  
  105.  
  106.         # If we're doing a 12-hr clock, there will be a meridiem value, so make sure the
  107.         # hours get printed correctly
  108.         if self.twelve_hr and self.meridiem_val:
  109.             if self.meridiem_val.lower().startswith('p') and hour_val > 12 and hour_val < 24:
  110.                 hour_val = hour_val % 12
  111.         elif hour_val == 0:
  112.             hour_val = 12
  113.  
  114.         output = []
  115.         if 'id' in self.attrs:
  116.             id_ = self.attrs['id']
  117.         else:
  118.             id_ = 'id_%s' % name
  119.  
  120.         # For times to get displayed correctly, the values MUST be converted to unicode
  121.         # When Select builds a list of options, it checks against Unicode values
  122.         hour_val = u"%.2d" % hour_val
  123.         minute_val = u"%.2d" % minute_val
  124.         #second_val = u"%.2d" % second_val
  125.  
  126.         hour_choices = [("%.2d"%i, "%.2d"%i) for i in self.hours]
  127.         local_attrs = self.build_attrs(id=self.hour_field % id_)
  128.         select_html = Select(choices=hour_choices).render(self.hour_field % name, hour_val, local_attrs)
  129.         output.append(select_html)
  130.  
  131.         minute_choices = [("%.2d"%i, "%.2d"%i) for i in self.minutes]
  132.         local_attrs['id'] = self.minute_field % id_
  133.         select_html = Select(choices=minute_choices).render(self.minute_field % name, minute_val, local_attrs)
  134.         output.append(select_html)
  135.  
  136.        
  137.         #second_choices = [("%.2d"%i, "%.2d"%i) for i in self.seconds]
  138.         #local_attrs['id'] = self.second_field % id_
  139.         #select_html = Select(choices=second_choices).render(self.second_field % name, second_val, local_attrs)
  140.         #output.append(select_html)
  141.  
  142.         if self.twelve_hr:
  143.             #  If we were given an initial value, make sure the correct meridiem gets selected.
  144.             if self.meridiem_val is not None and  self.meridiem_val.startswith('p'):
  145.                     meridiem_choices = [('p.m.','p.m.'), ('a.m.','a.m.')]
  146.             else:
  147.                 meridiem_choices = [('a.m.','a.m.'), ('p.m.','p.m.')]
  148.  
  149.             local_attrs['id'] = local_attrs['id'] = self.meridiem_field % id_
  150.             select_html = Select(choices=meridiem_choices).render(self.meridiem_field % name, self.meridiem_val, local_attrs)
  151.             output.append(select_html)
  152.  
  153.         return mark_safe(u'\n'.join(output))
  154.  
  155.     def id_for_label(self, id_):
  156.         return '%s_hour' % id_
  157.     id_for_label = classmethod(id_for_label)
  158.  
  159.     def value_from_datadict(self, data, files, name):
  160.         # if there's not h:m:s data, assume zero:
  161.         h = data.get(self.hour_field % name, 0) # hour
  162.         m = data.get(self.minute_field % name, 0) # minute
  163.         #s = data.get(self.second_field % name, 0) # second
  164.  
  165.         meridiem = data.get(self.meridiem_field % name, None)
  166.  
  167.         #NOTE: if meridiem is None, assume 24-hr
  168.         if meridiem is not None:
  169.             if meridiem.lower().startswith('p') and int(h) != 12:
  170.                 h = (int(h)+12)%24
  171.             elif meridiem.lower().startswith('a') and int(h) == 12:
  172.                 h = 0
  173.  
  174.         if (int(h) == 0 or h) and m:
  175.             return '%s:%s:%s' % (h, m, 0)
  176.  
  177.         return data.get(name, None)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement