Source code for core.widgets
"""
Provides extra HTML Widget classes
"""
import datetime
import re
from django.forms.widgets import Widget
from django.utils.dates import MONTHS, MONTHS_AP, MONTHS_3
from django.conf import settings
__all__ = ('SelectDateWidget',)
RE_DATE = re.compile(r'(\d{4})-(\d\d?)-(\d\d?)$')
[docs]class SelectDateWidget(Widget):
'''
A Widget that splits date input into three <select> boxes.
This also serves as an example of a Widget that has more than one HTML
element and hence implements value_from_datadict.
'''
# none_value = (0, '---')
# month_field = '%s_month'
# day_field = '%s_day'
# year_field = '%s_year'
date_format = [('year', 'Y'), ('day', 'j'), ('month', 'F')]
def __init__(self, attrs=None, years=None, format=None, required=True):
if attrs is None:
attrs = {}
self.attrs = attrs
self.values = {}
self.format = self.parse_format(format)
self.required = required
# years is an optional list/tuple of years to use in
# the "year" select box.
if years:
self.years = years
else:
this_year = datetime.date.today().year
self.years = list(range(this_year, this_year + 10))
super(SelectDateWidget, self).__init__(attrs)
[docs] def id_for_label(self, id_):
'''
Returns:
the label for this widget
'''
return '%s_month' % id_
id_for_label = classmethod(id_for_label)
[docs] def value_from_datadict(self, data, files, name):
'''
Returns:
the values from the post data based
associated with this widget
'''
y = data.get('%s_year' % name)
m = data.get('%s_month' % name)
d = data.get('%s_day' % name)
if y == m == d == '-1':
return None
if y and m and d:
return u'-'.join([y, m, d])
return data.get(name, None)
[docs] def parse_value(self, val):
'''
Returns:
An dict with month, day, year based on val or an empty dict
'''
ret = {}
if isinstance(val, datetime.date):
ret['month'] = val.month
ret['day'] = val.day
ret['year'] = val.year
else:
try:
l = list(map(int, val.split('-')))
except (ValueError, AttributeError):
l = (None, None, None)
for i, k in [(0, 'year'), (1, 'month'), (2, 'day')]:
try:
ret[k] = l[i]
except IndexError:
ret[k] = None
return ret
[docs] def parse_format(self, fmt):
'''
Parse the given format `fmt` and set the format property.
'''
if fmt is None:
fmt = settings.DATE_FORMAT
ret = []
for item in fmt:
if item in ['d', 'D', 'j', 'L']:
ret.append(('day', item,))
elif item in ['n', 'm', 'F', 'b', 'M', 'N']:
ret.append(('month', item,))
elif item in ['y', 'Y']:
ret.append(('year', item,))
return ret
[docs] def month_choices(self, fmt):
'''
Return list of choices (tuple (key, value)) for monthes select.
'''
if fmt == 'n':
# month numbers without leading 0 (1 .. 12)
return [(i, i) for i in range(1, 13)]
elif fmt == 'm':
# month numbers with leading 0 (01 .. 12)
return [(i, '%02d' % i) for i in range(1, 13)]
elif fmt in ['F', 'b', 'M', 'N']:
if fmt == 'F':
# full month names
month_choices = list(MONTHS.items())
elif fmt == 'b':
# 3 first letters of month lowercase
month_choices = [
(k, v.lower()) for (k, v) in
list(MONTHS_3.items())
]
elif fmt == 'M':
# 3 first letters of month
month_choices = list(MONTHS_3.items())
elif fmt == 'N':
# abbrev of month names
month_choices = list(MONTHS_AP.items())
month_choices.sort()
return month_choices
return []
[docs] def day_choices(self, fmt):
'''
Return list of choices (tuple (key, value)) for days select.
'''
if fmt == 'j':
# day of month number without leading 0
return [(i, i) for i in range(1, 32)]
elif fmt == 'd':
# day of month number with leading 0
return [(i, '%02d' % i) for i in range(1, 32)]
return []
[docs] def year_choices(self, fmt):
'''
Return list of choices (tuple (key, value)) for years select.
'''
if fmt == 'Y':
# years with 4 numbers
return [(i, i) for i in self.years]
elif fmt == 'y':
# years with only the last 2 numbers
return [(i, str(i)[-2:]) for i in self.years]
return []