I have a custom field called HourField, which lets you enter "1:30" to represent one and a half hours. The clean()
method turns it into 1.5 for the FloatField in the model. This all works fine. Now I'm having a problem where when I want to create a formset, that field gets rendered as "1.5" instead of "1:30" which is what I want.
Is there some kind of method similar to clean()
but works the other way around?
edit: using another type of storage method is out of the question. I have a few other custom fields I have made which are stored as one type of object, but are entered by the user as a string. I used the example above because it was the most straight forward.
To customize the way a field renders, you need to define a widget as well.
The following code shows some responsibilities of widgets in django :
Please note that the widget's code is inspired by widgets.TimeInput from the sourcecode of django, which helps being consistent.
from django import forms
from django.forms import widgets
from django.forms.util import ValidationError
class HourWidget(widgets.TextInput):
def _format_value(self, value):
if isinstance(value, float) or isinstance(value, int):
import math
hours = math.floor(value)
minutes = (value - hours) * 60
value = "%d:%02d" % (hours, minutes)
return value
def render(self, name, value, attrs=None):
value = self._format_value(value)
return super(HourWidget, self).render(name, value, attrs)
def _has_changed(self, initial, data):
return super(HourWidget, self)._has_changed(self._format_value(initial), data)
class HourField(forms.Field):
widget = HourWidget
def clean(self, value):
super(HourField, self).clean(value)
import re
match = re.match("^([0-9]{1,2}):([0-9]{2})$", value)
if not match:
raise ValidationError("Please enter a valid hour ( ex: 12:34 )")
groups = match.groups()
hour = float(groups[0])
minutes = float(groups[1])
if minutes >= 60:
raise ValidationError("Invalid value for minutes")
return hour + minutes/60
Please note that 1:20 becomes 1:19, which is due to the loss of precision induced by the use of a float. You might want to change the data type if you don't want to lose some precision.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With