# What is correct HTML input type or widget for DurationField?

**URL:** <https://forum.djangoproject.com/t/what-is-correct-html-input-type-or-widget-for-durationfield/15817>\
**Category:** Forms & APIs\
**Created:** [September 5, 2022, 4:56am UTC](https://forum.djangoproject.com/t/what-is-correct-html-input-type-or-widget-for-durationfield/15817 "2022-09-05T04:56:13Z")\
**Posts on this page:** 16\
**Page:** 1

<div class="post-metadata">

**Author:** ![Sweetbarrow](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/sweetbarrow/32/9633_2.png) [@Sweetbarrow](https://forum.djangoproject.com/u/Sweetbarrow)\
**Post date:** [September 5, 2022, 4:56am UTC](https://forum.djangoproject.com/t/what-is-correct-html-input-type-or-widget-for-durationfield/15817/1 "2022-09-05T04:56:13Z")

</div>

I’m making a form that users can input duration of time into the fields  
I set default values on these fields, and I set widget for these fields as `NumberInput`, because if I use HTML `input type="time"`, the browser shows AM/PM without additional style or scripting, and this might lead users to confuse about entering duration.  
So, I use `NumberInput` and additional `clean_<field>` to handle this  
This don’t show default value on the input.  
What I want to know is, which HTML input type or widget should I use to show users default value and make them not confused.

**models.py**

```auto
import datetime

from django.core.validators import RegexValidator
from django.db import models
from django.urls import reverse

# Create your models here.
...
class Branch(models.Model):
...
    lesson_time = models.DurationField(
        verbose_name="Lesson time",
        default=datetime.timedelta(minutes=110),
    )
    break_time = models.DurationField(
        verbose_name="Break time",
        default=datetime.timedelta(minutes=10),
    )
...

```

**forms.py**

```auto
import datetime

from django import forms
from django.forms import ModelForm

from branches.models import Branch, Hour

class BranchForm(ModelForm):
...
    def clean_lesson_time(self):
        time = self.data["lesson_time"]
        return datetime.timedelta(minutes=int(time))

    def clean_break_time(self):
        time = self.data["break_time"]
        return datetime.timedelta(minutes=int(time))
...
    class Meta:
        model = Branch
        fields = (
...
            "lesson_time",
            "break_time",
        )
...
            "lesson_time": forms.NumberInput(
                attrs={
                    "aria-describedby": "minute-unit",
                    "class": "form-control",
                }
            ),
            "break_time": forms.NumberInput(
                attrs={
                    "aria-describedby": "minute-unit",
                    "class": "form-control",
                }
            ),
        }

```

**branch\_form.html**

```auto
<!DOCTYPE html>
{% extends "main/base.html" %}
{% load static %}
{% block content %}
    <form action="" method="POST" id="branch-form" class="container d-grid gap-3 justify-content-evenly align-items-center">
        {% csrf_token %}
        {{ form.non_field_errors }}        
...        
        <div class="row">
            <label class="col-3 col-form-label text-nowrap" for="{{ form.lesson_time.id_for_label }}">{{ form.lesson_time.label }}</label>
            <div class="col input-group">{{ form.lesson_time }}
                <span class="input-group-text">minutes</span>
            </div>
            {{ form.lesson_time.errors }}
        </div>
        
        <div class="row">
            <div class="col d-flex justify-content-end">
                <p>
                    &#8251; Enter length of lesson time in minutes.<br>
                    Default value is 110 minutes.
                </p>
            </div>
        </div>
        
        <div class="row">
            <label class="col-3 col-form-label text-nowrap" for="{{ form.break_time.id_for_label }}">{{ form.break_time.label }}</label>
            <div class="col input-group">{{ form.break_time }}<span class="input-group-text">Minutes</span></div>
            {{ form.break_time.errors }}
        </div>
        
        <div class="row">
            <div class="col d-flex justify-content-end">
                <p>
                    &#8251; Enter length of break time in minutes.<br>
                    Default value is 10 minutes.
                </p>
            </div>
        </div>
...
{% endblock %}

```

---

<div class="post-metadata">

**Author:** ![plopidou](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/plopidou/32/5148_2.png) [@plopidou](https://forum.djangoproject.com/u/plopidou)\
**Post date:** [September 5, 2022, 9:52am UTC](https://forum.djangoproject.com/t/what-is-correct-html-input-type-or-widget-for-durationfield/15817/2 "2022-09-05T09:52:46Z")

</div>

This is not django-related but I would have a `DurationField` set as a number input in the background, i.e, hidden via CSS. Or even as a hidden input.

The (most granular) unit of this field you can choose in an arbitrary way: could be seconds, hours, days or milliseconds.

Then I would enhance the lot with Javascript, i.e., purely client-side. Ideas:

- split hidden field in several fields that can be interacted with. “Virtual fields” such as one for days, one for hours, etc. Similar to the `deconstruct` or `to_python` methods server-side.
- do conversions client-side in real time. For example, if user enters 1 days and you hidden field is in seconds, add 24_60_60 to the hidden field.

In that way you would ensure a simple number to reach your server as, say, a number of seconds.

OR

you could split you values in `form.py`, with optional fields taking care of each “unit”: days, hours, minutes, seconds, etc. Then transform in some `clean` methods server-side.

Up to you, there are probably a hundred different ways of doing that.

---

<div class="post-metadata">

**Author:** ![Spha](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/spha/32/9509_2.png) [@Spha](https://forum.djangoproject.com/u/Spha)\
**Post date:** [September 7, 2022, 12:12pm UTC](https://forum.djangoproject.com/t/what-is-correct-html-input-type-or-widget-for-durationfield/15817/3 "2022-09-07T12:12:34Z")

</div>

Have you tried TimeInput as a widget type? I have not tried it myself as I had abandoned using DurationField (and used IntegerField instead)

[https://docs.djangoproject.com/en/4.1/ref/forms/widgets/#timeinput](https://docs.djangoproject.com/en/4.1/ref/forms/widgets/#timeinput)

It could be worth experimenting with TIME\_INPUT\_FORMATS in **settings.py** also:  
[https://docs.djangoproject.com/en/4.1/ref/settings/#std-setting-TIME\_INPUT\_FORMATS](https://docs.djangoproject.com/en/4.1/ref/settings/#std-setting-TIME_INPUT_FORMATS)

---

<div class="post-metadata">

**Author:** ![Sweetbarrow](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/sweetbarrow/32/9633_2.png) [@Sweetbarrow](https://forum.djangoproject.com/u/Sweetbarrow)\
**Post date:** [September 7, 2022, 2:52pm UTC](https://forum.djangoproject.com/t/what-is-correct-html-input-type-or-widget-for-durationfield/15817/4 "2022-09-07T14:52:04Z")

</div>

Well, I tried `TimeInput` with `attrs = {"type": "time"}`.  
The result of that was the time with AM/PM

---

<div class="post-metadata">

**Author:** ![KenWhitesell](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/kenwhitesell/32/280_2.png) [@KenWhitesell](https://forum.djangoproject.com/u/KenWhitesell)\
**Post date:** [September 7, 2022, 4:00pm UTC](https://forum.djangoproject.com/t/what-is-correct-html-input-type-or-widget-for-durationfield/15817/5 "2022-09-07T16:00:02Z")

</div>

On Windows, the 12- or 24-hour format is determined by System Settings / Region / Date and time formats.

For example, with the 12-hour setting, this page, [\<input type="time"\> - HTML: HyperText Markup Language | MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/time), looks like this:

 ![24 hour time](https://us1.discourse-cdn.com/flex026/uploads/djangoproject/original/2X/7/77e57406e4ee2a154cb7d96f29850825c26d5513.png)

But if I change my system settings, it displays like this:

 ![24hourtime](https://us1.discourse-cdn.com/flex026/uploads/djangoproject/original/2X/b/b0dbf1d4290e5d1ed2381a9efb92a8fa478b3469.png)

In other words, this appears to be something that is not under control of the HTML on the page.

(Note: Also read the text on the referenced page for more detailed information.)

I’d have to second @plopidou here - I think the only reasonable way to produce a platform and settings-independent widget for a duration would be to craft it yourself using a text input widget and some JavaScript.

---

<div class="post-metadata">

**Author:** ![Spha](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/spha/32/9509_2.png) [@Spha](https://forum.djangoproject.com/u/Spha)\
**Post date:** [September 7, 2022, 4:56pm UTC](https://forum.djangoproject.com/t/what-is-correct-html-input-type-or-widget-for-durationfield/15817/6 "2022-09-07T16:56:00Z")

</div>

may I ask - what duration format exactly do you want to work with? days/minutes/hours/seconds or just minutes? if this was just minutes (for input and output), you could really lower the complexity of everything

---

<div class="post-metadata">

**Author:** ![Sweetbarrow](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/sweetbarrow/32/9633_2.png) [@Sweetbarrow](https://forum.djangoproject.com/u/Sweetbarrow)\
**Post date:** [September 8, 2022, 12:09am UTC](https://forum.djangoproject.com/t/what-is-correct-html-input-type-or-widget-for-durationfield/15817/7 "2022-09-08T00:09:02Z")

</div>

I want to show only minutes like 110 minutes for 1 hour 50 minutes.

---

<div class="post-metadata">

**Author:** ![Sweetbarrow](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/sweetbarrow/32/9633_2.png) [@Sweetbarrow](https://forum.djangoproject.com/u/Sweetbarrow)\
**Post date:** [September 8, 2022, 12:10am UTC](https://forum.djangoproject.com/t/what-is-correct-html-input-type-or-widget-for-durationfield/15817/8 "2022-09-08T00:10:43Z")

</div>

I’ve already read the documentation from MDN.  
So, is it mean there is no simple way to achieve what I want?

---

<div class="post-metadata">

**Author:** ![KenWhitesell](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/kenwhitesell/32/280_2.png) [@KenWhitesell](https://forum.djangoproject.com/u/KenWhitesell)\
**Post date:** [September 8, 2022, 12:13am UTC](https://forum.djangoproject.com/t/what-is-correct-html-input-type-or-widget-for-durationfield/15817/9 "2022-09-08T00:13:29Z")

</div>

Correct. There is no HTML element or attribute to handle a duration field as a duration.

---

<div class="post-metadata">

**Author:** ![Sweetbarrow](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/sweetbarrow/32/9633_2.png) [@Sweetbarrow](https://forum.djangoproject.com/u/Sweetbarrow)\
**Post date:** [September 8, 2022, 1:11am UTC](https://forum.djangoproject.com/t/what-is-correct-html-input-type-or-widget-for-durationfield/15817/10 "2022-09-08T01:11:01Z")

</div>

Can I assume that the only way to reflect default value in `models.py` is `<input type="time">`?

---

<div class="post-metadata">

**Author:** ![KenWhitesell](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/kenwhitesell/32/280_2.png) [@KenWhitesell](https://forum.djangoproject.com/u/KenWhitesell)\
**Post date:** [September 8, 2022, 1:39am UTC](https://forum.djangoproject.com/t/what-is-correct-html-input-type-or-widget-for-durationfield/15817/11 "2022-09-08T01:39:00Z")

</div>

I don’t think I understand what you’re asking here.

What you see on a form on a page does not need to have _any_ relationship to the data as it is stored in the model.

A [DurationField](https://docs.djangoproject.com/en/4.1/ref/models/fields/#durationfield) in a model is stored in the database as an `interval` on PostgreSQL and Oracle and as a `bigint` everywhere else.

In the model objects themselves, it’s stored as a [`timedelta`](https://docs.python.org/3/library/datetime.html#timedelta-objects) object, which is _not_ a datetime field. And, unfortunately, there is no HTML representation of a “duration”.

The Django [`DurationField`](https://docs.djangoproject.com/en/4.1/ref/forms/fields/#durationfield) defaults to a text input that has to be parsed by the [`parse_duration`](https://docs.djangoproject.com/en/4.1/ref/utils/#django.utils.dateparse.parse_duration) function.

---

<div class="post-metadata">

**Author:** ![Sweetbarrow](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/sweetbarrow/32/9633_2.png) [@Sweetbarrow](https://forum.djangoproject.com/u/Sweetbarrow)\
**Post date:** [September 8, 2022, 3:26am UTC](https://forum.djangoproject.com/t/what-is-correct-html-input-type-or-widget-for-durationfield/15817/12 "2022-09-08T03:26:13Z")

</div>

No, I think you’ve understood what I’m asking.  
Because of my lack of knowledge about Django, I’m a bit confused and I just wanted to make it clear.  
What I’m trying to make is if user just enter ‘110’, system recognize it as 110 minutes and store as `timedelta(minutes=110)`.

---

<div class="post-metadata">

**Author:** ![KenWhitesell](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/kenwhitesell/32/280_2.png) [@KenWhitesell](https://forum.djangoproject.com/u/KenWhitesell)\
**Post date:** [September 8, 2022, 3:57am UTC](https://forum.djangoproject.com/t/what-is-correct-html-input-type-or-widget-for-durationfield/15817/13 "2022-09-08T03:57:55Z")

</div>

First, all of your choices are going to involve _some_ amount of writing code to do this. That format is not going to be directly handled by Django.

You have a couple different options

- Create a [custom field](https://docs.djangoproject.com/en/4.1/howto/custom-model-fields/#how-to-create-custom-model-fields) with a custom `to_python` method.

- Translate the text field in JavaScript to a `parse_duration` compatible format before submitting the form.

- Create a separate field for the Form entry and perform the conversion in either `Form.clean` or `ModelForm.save`.

… and I’m sure there are other options as well. You can add code pretty much anywhere along the line here to perform your conversion before the data gets saved to the database.

---

<div class="post-metadata">

**Author:** ![Sweetbarrow](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/sweetbarrow/32/9633_2.png) [@Sweetbarrow](https://forum.djangoproject.com/u/Sweetbarrow)\
**Post date:** [September 8, 2022, 4:18am UTC](https://forum.djangoproject.com/t/what-is-correct-html-input-type-or-widget-for-durationfield/15817/14 "2022-09-08T04:18:33Z")

</div>

Thank you for your answer.  
My current solution(using `NumberInput` for widget and handle with `clean_<field>` method) works well, so I can keep it.

---

<div class="post-metadata">

**Author:** ![Spha](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/spha/32/9509_2.png) [@Spha](https://forum.djangoproject.com/u/Spha)\
**Post date:** [September 8, 2022, 7:37am UTC](https://forum.djangoproject.com/t/what-is-correct-html-input-type-or-widget-for-durationfield/15817/15 "2022-09-08T07:37:43Z")

</div>

If it helps, we did this before with an IntegerField and javascript to output minutes from days/hours/minutes (it outputs the minutes directly into the form field)

the JS code goes in `static/js/script.js`

```auto
function add_number() {

    const day_number = parseInt((document.getElementById("DayConversion").value)* 1440 || 0) ; // 0 or get day value multiplied by minutes per day 
    const hour_number = parseInt(document.getElementById("HourConversion").value * 60 || 0); // 0 or get hour value multiplied by minutes per hour
    const minute_number = parseInt(document.getElementById("MinuteConversion").value) || 0; // 0 or get minutes value

    document.getElementById("id_downtime").value = day_number + hour_number + minute_number; // total value of minutes -> html element 
}

```

the html template contains this:

```auto
<div class="card-body">
                                                                <div class="row ">
                                                                        <div class="col-md-8 ">
                                                                                <div class="input-group">

                                                                                        <input type="number" class="form-control" placeholder="DD" aria-label="Days" id="DayConversion" oninput="add_number()">
                                                                                        <span class="input-group-text"> : </span>
                                                                                        <input type="number" class="form-control" placeholder="HH" aria-label="Hours" id="HourConversion" oninput="add_number()">
                                                                                        <span class="input-group-text"> : </span>
                                                                                        <input type="number" class="form-control" placeholder="MM" aria-label="Minutes" id="MinuteConversion" oninput="add_number()">

                                                                                </div>
                                                                        </div>

                                                                        <div class="col-md-4 ">
                                                                                        {{ form.downtime}}
                                                                        </div>
                                                                </div>
                                                        </div>

```

and as for the widget for the form field (downtime), it was just NumberInput  
`"downtime" : forms.NumberInput(attrs={'class':'form-control', 'placeholder':'Total Downtime'}),`

---

<div class="post-metadata">

**Author:** ![Sweetbarrow](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/sweetbarrow/32/9633_2.png) [@Sweetbarrow](https://forum.djangoproject.com/u/Sweetbarrow)\
**Post date:** [September 8, 2022, 8:22am UTC](https://forum.djangoproject.com/t/what-is-correct-html-input-type-or-widget-for-durationfield/15817/16 "2022-09-08T08:22:11Z")

</div>

Okay, thanks.  
I will look into it.
