Я хочу иметь поле и виджет, который позволяет иметь «приблизительную» дату, идея состоит в том, чтобы иметь одно-единственное из следующего:
- Точная дата
- Год, а может и месяц
- Начальный и конечный год
Некоторые сжатые допустимые значения могут быть:
- "1988/08/07 ,,,,"
- "1988 ,,,"
- "1988,08 ,,"
- »,,, 1997,1999"
Проблема в том, что я не могу проверить поля, чтобы иметь только один из трех вариантов, описанных выше, в определении поля я попытался создать методы проверки и очистки, но проверка не проходит, я подозреваю, что связь между поля и виджеты не правильно. Чего мне не хватает?
Для этого я создал виджет:
class ApproximatedDateWidget(forms.MultiWidget):
def __init__(self, attrs=None,choices=()):
self.widgets = (
forms.DateInput(attrs=attrs),
forms.TextInput(attrs=attrs),
forms.Select(attrs=attrs,choices=choices),
forms.TextInput(attrs=attrs),
forms.TextInput(attrs=attrs),
)
super(ApproximatedDateWidget, self).__init__(self.widgets, attrs=attrs)
def decompress(self,value):
try :
print value
if value:
l=value.split(",")
print l
if l[0] and l[0]!="":
d=l[0].split("/")
print d
return [date(int(d[0]),int(d[1]),int(d[2])),None,None,None,None]
else:
return [None, l[1], l[2], l[3], l[4]]
return [None, None, None, None, None]
except:
raise
return [None, None, None, None, None]
def format_output(self,rendered_widgets):
return mark_safe(u"""<table>
<tr><td>Exact date:</td><td colspan="3">{0}</td></tr>
<tr><td>Year and month:</td><td>{1}</td><td colspan="2">{2}</td></tr>
<tr><td></td><td>Year</td><td colspan="2">Month</td></tr>
<tr><td>Between:</td><td>{3}</td><td>and</td><td>{4}</td></tr>
<tr><td></td><td>Year</td><td></td><td>Year<td></tr>
</table>
""".format(*rendered_widgets))
И Поле формы:
from tools import MonthChoices
from validators import nullableinteger
class ApproximatedDateField(forms.MultiValueField):
"""
Field that allows having an approximated date, one of
exact date, month and year or range of years
"""
def __init__(self, required=False, widget=None, label=None, initial=None,
help_text=None,attrs={}, *args, **kwargs):
self.widget = ApproximatedDateWidget(attrs=attrs,choices=MonthChoices)
widgets=self.widget.widgets
fields = (
forms.DateField(required=required,validators=[lessthantomorrow],widget=widgets[0]),
forms.CharField(widget=widgets[1],required=required,max_length=4,validators=[nullableinteger]),
forms.ChoiceField(required=required,choices=MonthChoices,widget=widgets[2]),
forms.CharField(widget=widgets[3],required=required,max_length=4,validators=[nullableinteger]),
forms.CharField(widget=widgets[4],required=required,max_length=4,validators=[nullableinteger]),
)
super(ApproximatedDateField, self).__init__(fields=fields,required=required, widget=widget,
label=label, initial=initial, help_text=help_text)
def compress(self,data_list):
return """{0},{1},{2},{3},{4}""".format(data_list[0].strftime("%d/%m/%Y"),data_list[1],(data_list[2] and data_list[2].id) or "",data_list[3],data_list[4])
def validate(self,values):
super(ApproximatedDateField, self).validate(values)
if values[0] is not None and (values[1] is not None or values[2] is not None) and (values[1] is not None or values[2] is not None):
raise ValidationError(u'Please only fill exact date or year and month or the range years')
def clean(self,values):
super(ApproximatedDateField, self).clean(values)
if values[0] is not None and (values[1] is not None or values[2] is not None) and (values[1] is not None or values[2] is not None):
raise ValidationError(u'Please only fill exact date or year and month or the range years')