|
0
|
1 |
""" |
|
|
2 |
Extra HTML Widget classes |
|
|
3 |
""" |
|
|
4 |
|
|
|
5 |
import datetime |
|
|
6 |
import re |
|
|
7 |
|
|
|
8 |
from django.forms.widgets import Widget, Select |
|
|
9 |
from django.utils.dates import MONTHS |
|
|
10 |
from django.utils.safestring import mark_safe |
|
|
11 |
|
|
|
12 |
__all__ = ('SelectDateWidget',) |
|
|
13 |
|
|
|
14 |
RE_DATE = re.compile(r'(\d{4})-(\d\d?)-(\d\d?)$') |
|
|
15 |
|
|
|
16 |
class SelectDateWidget(Widget): |
|
|
17 |
""" |
|
|
18 |
A Widget that splits date input into three <select> boxes. |
|
|
19 |
|
|
|
20 |
This also serves as an example of a Widget that has more than one HTML |
|
|
21 |
element and hence implements value_from_datadict. |
|
|
22 |
""" |
|
|
23 |
none_value = (0, '---') |
|
|
24 |
month_field = '%s_month' |
|
|
25 |
day_field = '%s_day' |
|
|
26 |
year_field = '%s_year' |
|
|
27 |
|
|
|
28 |
def __init__(self, attrs=None, years=None, required=True): |
|
|
29 |
# years is an optional list/tuple of years to use in the "year" select box. |
|
|
30 |
self.attrs = attrs or {} |
|
|
31 |
self.required = required |
|
|
32 |
if years: |
|
|
33 |
self.years = years |
|
|
34 |
else: |
|
|
35 |
this_year = datetime.date.today().year |
|
|
36 |
self.years = range(this_year, this_year+10) |
|
|
37 |
|
|
|
38 |
def render(self, name, value, attrs=None): |
|
|
39 |
try: |
|
|
40 |
year_val, month_val, day_val = value.year, value.month, value.day |
|
|
41 |
except AttributeError: |
|
|
42 |
year_val = month_val = day_val = None |
|
|
43 |
if isinstance(value, basestring): |
|
|
44 |
match = RE_DATE.match(value) |
|
|
45 |
if match: |
|
|
46 |
year_val, month_val, day_val = [int(v) for v in match.groups()] |
|
|
47 |
|
|
|
48 |
output = [] |
|
|
49 |
|
|
|
50 |
if 'id' in self.attrs: |
|
|
51 |
id_ = self.attrs['id'] |
|
|
52 |
else: |
|
|
53 |
id_ = 'id_%s' % name |
|
|
54 |
|
|
|
55 |
month_choices = MONTHS.items() |
|
|
56 |
if not (self.required and value): |
|
|
57 |
month_choices.append(self.none_value) |
|
|
58 |
month_choices.sort() |
|
|
59 |
local_attrs = self.build_attrs(id=self.month_field % id_) |
|
|
60 |
s = Select(choices=month_choices) |
|
|
61 |
select_html = s.render(self.month_field % name, month_val, local_attrs) |
|
|
62 |
output.append(select_html) |
|
|
63 |
|
|
|
64 |
day_choices = [(i, i) for i in range(1, 32)] |
|
|
65 |
if not (self.required and value): |
|
|
66 |
day_choices.insert(0, self.none_value) |
|
|
67 |
local_attrs['id'] = self.day_field % id_ |
|
|
68 |
s = Select(choices=day_choices) |
|
|
69 |
select_html = s.render(self.day_field % name, day_val, local_attrs) |
|
|
70 |
output.append(select_html) |
|
|
71 |
|
|
|
72 |
year_choices = [(i, i) for i in self.years] |
|
|
73 |
if not (self.required and value): |
|
|
74 |
year_choices.insert(0, self.none_value) |
|
|
75 |
local_attrs['id'] = self.year_field % id_ |
|
|
76 |
s = Select(choices=year_choices) |
|
|
77 |
select_html = s.render(self.year_field % name, year_val, local_attrs) |
|
|
78 |
output.append(select_html) |
|
|
79 |
|
|
|
80 |
return mark_safe(u'\n'.join(output)) |
|
|
81 |
|
|
|
82 |
def id_for_label(self, id_): |
|
|
83 |
return '%s_month' % id_ |
|
|
84 |
id_for_label = classmethod(id_for_label) |
|
|
85 |
|
|
|
86 |
def value_from_datadict(self, data, files, name): |
|
|
87 |
y = data.get(self.year_field % name) |
|
|
88 |
m = data.get(self.month_field % name) |
|
|
89 |
d = data.get(self.day_field % name) |
|
|
90 |
if y == m == d == "0": |
|
|
91 |
return None |
|
|
92 |
if y and m and d: |
|
|
93 |
return '%s-%s-%s' % (y, m, d) |
|
|
94 |
return data.get(name, None) |