1

In my form I am expecting the user to enter a two part time...HH:mm but when the update form is loaded the duration field value is returned as HH:mm:ss

So when saving a value:

duration: 13:00

When editing the form the initial data will be:

duration 13:00:00

When saving that I get an ValidationError as that is not a format I want to accept.

            if ':' in duration:
                try:
                    (hours, minutes,) = duration.split(':')
                except ValueError:
                    self.add_error(
                        'duration',
                        _("Invalid duration: {}".format(duration))
                    )
                    return duration

Is there a way to only show the HH:mm format for all places I am showing the DurationField or is it better to just set it in the initial data of the form?

tread
  • 10,133
  • 17
  • 95
  • 170

1 Answers1

2

If you're using a DurationField why do you add validation? The validation provided by Django should work and will accept '13:00' as input as well as '13:00:00'. Just add a placeholder text like '13:00' to your widget so your user knows what to enter but don't add obstacles by forbidding '13:00:00'.

If you're using a ModelForm, in the Meta class:

widgets = {'duration': TextInput(attrs={'placeholder': '13:00'})}

Internally, your duration is saved as datetime.timedelta so you should just validate on valid durations you want to accept (like no more than 12 hours...). And whereever you need to output the duration, you can format it as you wish (e.g. see this SO thread on the subject).

To override how the value is displayed in your input field, you should subclass forms.DurationField:

from django.utils.duration import _get_duration_components

def hhmm_duration_string(duration):
    days, hours, minutes, seconds, microseconds = 
       _get_duration_components(duration)

    string = '{:02d}:{:02d}'.format(hours, minutes)
    return string

class HHMMDurationField(forms.DurationField):
    def prepare_value(self, value):
        if isinstance(value, datetime.timedelta):
            return hhmm_duration_string(value)
        return value
dirkgroten
  • 20,112
  • 2
  • 29
  • 42
  • The requirement was entering time as a decimal and a time field. Also min and max value validators don't work on `DurationFields` so have had to make a few concessions although using the out the box field is always my preference – tread Dec 01 '17 at 21:44
  • You can always validate min, max in your form using the `clean_duration()` method, so I don't see the problem with validation. Also since your HTML input field is a text input field, it would be nice to your users to give them flexibility of input (while telling them as an example that 13:00 is the expected input). Better yet, if you really want to make it easy, is to let them enter hours and minutes in two separate input fields (subclass `MultiValueField` for the field and `MultiWidget` for the widget). – dirkgroten Dec 03 '17 at 16:06
  • 1
    I like your answer, keep it standard. It is now about convincing the client to not enter time in the `5.5` decimal format. – tread Dec 05 '17 at 13:35