Ticket #16575: widgets.py

File widgets.py, 3.9 KB (added by anonymous, 13 years ago)
Line 
1"""
2Extra HTML Widget classes
3"""
4
5import time
6import datetime
7import re
8
9from django.forms.widgets import Widget, Select
10from django.utils import datetime_safe
11from django.utils.dates import MONTHS
12from django.utils.safestring import mark_safe
13from django.utils.formats import get_format
14from django.conf import settings
15
16__all__ = ('SelectDateWidget',)
17
18RE_DATE = re.compile(r'(\d{4})-(\d\d?)-(\d\d?)$')
19
20def _parse_format(fmt):
21 def pos(s):
22 match = re.search('[' + s + ']', fmt)
23 return match.start() + 1 if match else 0
24
25 dic = {'day': pos('dj'), 'month': pos('bEFMmNn'), 'year': pos('yY')}
26 return sorted(filter(None, dic.keys()), key=dic.get)
27
28def _parse_date_fmt():
29 return _parse_format(re.subn(r'\\.', '', get_format('DATE_FORMAT'))[0])
30
31
32class SelectDateWidget(Widget):
33 """
34 A Widget that splits date input into three <select> boxes.
35
36 This also serves as an example of a Widget that has more than one HTML
37 element and hence implements value_from_datadict.
38 """
39 names = ('day', 'month', 'year',)
40 none_values_dafault = '---'
41 field_values = ['%s_' + n for n in names]
42 fields = dict(zip(names, field_values))
43 day_field, month_field, year_field = field_values
44
45 def __init__(self, attrs=None, years=None, required=True,
46 date_format='', none_values=None):
47 # years is an optional list/tuple of years
48 # to use in the "year" select box.
49 self.attrs = attrs or {}
50 self.required = required
51 if not years:
52 this_year = datetime.date.today().year
53 years = range(this_year, this_year+10)
54 print list(years)
55 self.years = years
56 self.date_format = _parse_format(date_format)
57 self.none_values = none_values \
58 or dict([(i, self.none_values_dafault) for i in 'dmy'])
59
60 def render(self, name, value, attrs=None):
61
62 get_names_dict = lambda l: dict(zip(self.names, l))
63
64 try:
65 values_list = [getattr(value, n) for n in self.names]
66 except AttributeError:
67 values_list = []
68 if isinstance(value, basestring):
69 if settings.USE_L10N:
70 try:
71 input_format = get_format('DATE_INPUT_FORMATS')[0]
72 v = datetime.datetime.strptime(value, input_format)
73 values_list = [getattr(v, n) for n in self.names]
74 except ValueError:
75 pass
76 else:
77 match = RE_DATE.match(value)
78 if match:
79 values_list = (int(v) for v in match.groups())
80 values = get_names_dict(values_list)
81
82 choices = get_names_dict([
83 [(i, i) for i in range(1, 32)],
84 MONTHS.items(),
85 [(i, i) for i in self.years],
86 ])
87
88 create_select_short = lambda n: self.create_select(
89 name, self.fields[n], value, values.get(n), choices[n], n
90 )
91
92 htmls = get_names_dict([create_select_short(n) for n in self.names])
93
94 date_format = self.date_format or _parse_date_fmt()
95 output = [htmls[field] for field in date_format]
96 return mark_safe(u'\n'.join(output))
97
98 def id_for_label(cls, id_):
99 field_list = _parse_date_fmt()
100 if field_list:
101 first_select = field_list[0]
102 else:
103 first_select = 'month'
104 return '%s_%s' % (id_, first_select)
105 id_for_label = classmethod(id_for_label)
106
107 def value_from_datadict(self, data, files, name):
108 d, m, y = (data.get(self.fields[n] % name) for n in self.names)
109 if y == m == d == "0":
110 return None
111 if not (y and m and d):
112 return data.get(name)
113 if not settings.USE_L10N:
114 return '%s-%s-%s' % (y, m, d)
115 input_format = get_format('DATE_INPUT_FORMATS')[0]
116 try:
117 date_value = datetime.date(int(y), int(m), int(d))
118 date_value = datetime_safe.new_date(date_value)
119 return date_value.strftime(input_format)
120 except ValueError:
121 return '%s-%s-%s' % (y, m, d)
122
123 def create_select(self, name, field, value, val, choices, date_part='d'):
124 if 'id' in self.attrs:
125 id_ = self.attrs['id']
126 else:
127 id_ = 'id_%s' % name
128 if not (self.required and val):
129 choices.insert(0, (0, self.none_values[date_part[0]]))
130 local_attrs = self.build_attrs(id=field % id_)
131 s = Select(choices=choices)
132 select_html = s.render(field % name, val, local_attrs)
133 return select_html
134
Back to Top