Reputation:
Difficulty using the new DurationField in Django 1.8
I'm having a bit of trouble with Django's new DurationField for models.
I want the user to be able to choose if the duration of an event on my webapp is 1 day, 3 days, or 5 days, with the default choice being 3 days.
At the beginning of my model, I declare the choices:
SHORT = datetime.timedelta(days=1)
MEDIUM = datetime.timedelta(days=3)
LONG = datetime.timedelta(days=5)
DURATION_CHOICES = ((SHORT, '1 day'),(MEDIUM, '3 days'), (LONG, '5 days'),)
Then below, I declare the DurationField:
duration = models.DurationField(choices = DURATION_CHOICES, default = MEDIUM)
I created a ModelForm for the model, and rendered it on the appropriate template. On the form, "3 days" was the preselected choice in the dropdown, and "1 day" and "5 days" are options as well. However, when I submit the form, I get the form validation error "Select a valid choice. 3 days, 0:00:00 is not one of the available choices."
However, when I remove the choices from DurationField and leave the default:
duration = models.DurationField(default = MEDIUM)
I can submit without any issues. What am I doing wrong here?
Upvotes: 8
Views: 9857
Reputation: 313
Did had the same problem the problem is explained in this bugfix ticket
https://code.djangoproject.com/ticket/24897
best way to fix this is to use this custom field while waiting the django team to fix that:
"""
This is a temp DurationField with a bugfix
"""
standard_duration_re = re.compile(
r'^'
r'(?:(?P<days>-?\d+) (days, )?)?'
r'((?:(?P<hours>\d+):)(?=\d+:\d+))?'
r'(?:(?P<minutes>\d+):)?'
r'(?P<seconds>\d+)'
r'(?:\.(?P<microseconds>\d{1,6})\d{0,6})?'
r'$'
)
# Support the sections of ISO 8601 date representation that are accepted by
# timedelta
iso8601_duration_re = re.compile(
r'^P'
r'(?:(?P<days>\d+(.\d+)?)D)?'
r'(?:T'
r'(?:(?P<hours>\d+(.\d+)?)H)?'
r'(?:(?P<minutes>\d+(.\d+)?)M)?'
r'(?:(?P<seconds>\d+(.\d+)?)S)?'
r')?'
r'$'
)
def parse_duration(value):
"""Parses a duration string and returns a datetime.timedelta.
The preferred format for durations in Django is '%d %H:%M:%S.%f'.
Also supports ISO 8601 representation.
"""
match = standard_duration_re.match(value)
if not match:
match = iso8601_duration_re.match(value)
if match:
kw = match.groupdict()
if kw.get('microseconds'):
kw['microseconds'] = kw['microseconds'].ljust(6, '0')
kw = {k: float(v) for k, v in six.iteritems(kw) if v is not None}
return datetime.timedelta(**kw)
class DurationField(CoreDurationField):
def to_python(self, value):
if value is None:
return value
if isinstance(value, datetime.timedelta):
return value
try:
parsed = parse_duration(value)
except ValueError:
pass
else:
if parsed is not None:
return parsed
raise exceptions.ValidationError(
self.error_messages['invalid'],
code='invalid',
params={'value': value},
)
Upvotes: 2
Reputation: 10305
Somehow model choices
option not given timedelta
string when render
or convert into template
.
And the Model
DurationField
Field
DurationField
Not working...
I solved it by using ChoiceField
Code:
class TestForm(ModelForm):
SHORT_1 = str(timedelta(days=1)).replace('day,', '')
SHORT = SHORT_1.replace(' ',' ')
MEDIUM_1 = str(timedelta(days=3)).replace('days,', '')
MEDIUM = MEDIUM_1.replace(' ',' ')
LONG_1 = str(timedelta(days=-5)).replace('days,', '')
LONG = LONG_1.replace(' ',' ')
DURATION_CHOICES = ((SHORT, '1 day'),(MEDIUM, '3 days'), (LONG, '5 days'),)
duration = forms.ChoiceField(widget = forms.Select(),
choices = (DURATION_CHOICES), initial='MEDIUM', required = True,)
class Meta:
model = Test
fields = ['duration']
I don't know it's not recommended or not... I'm too searching why django defaultly not working ...
Upvotes: 0