Specifying the value format for a Django DateTimeInput using type=”datetime-local”, especially when using inline formsets

TL;DR: For a DateTimeInput widget where type=’datetime-local’, specify the default format to include the T in the middle of the date-time string:

widgets={
   'when':forms.DateTimeInput(
       format='%Y-%m-%dT%H:%M:%S',  
       attrs={'type':'datetime-local'} 
    ),
    ...
}

This was driving me crazy!

I had a model inline formset using a form:

forms.py:

TicketNoteFormset = inlineformset_factory(Ticket, TicketNote, form=TicketNoteForm, extra=10)

The specified form (TicketNoteForm) had a widget specified for a DateTime field:

forms.py:

class TicketTicketNoteForm(forms.ModelForm):
    class Meta:
        model = TicketNote
        fields = [
            'when',
            'text',
        ]
        widgets={
            'when':forms.DateInput(attrs={'type':'date'}),
            'text':forms.TextInput(attrs={'class':'len100'})
        }

My mistake was using DateInput for the field ‘when’, which was a DateTimeField, not a DateField
models.py:

class TicketNote(models.Model):

    when = models.DateTimeField(
        'when',
        default=datetime.now,
        help_text='The date that the note was submitted'
    )

In the HTML forms, the initial value, as expected, was a date-time value but the value attribute of the field was a date value without the time


<input type="date" name="ticketnote_set-0-when" value="2022-01-22 06:52:09" id="id_ticketnote_set-0-when">
<input type="hidden" name="initial-ticketnote_set-0-when" value="2022-01-22 06:52:09" id="initial-ticketnote_set-0-id_ticketnote_set-0-when">
    

The difference between initial and non-initial caused a record to be created even if the form was blank

But it was still broken after I fixed it

Leaving out the widget declaration works, but then I just get a plain text field and I want to take advantage of the browser’s popup calendar

I thought I had the problem fixed by specifying the widget as

forms.py:

DateTimeInput(attrs={'type':'datetime-local'}), 

but that’s still giving me some problems. It worked fine in Firefox, but Chrome ignored the value attribute. So in Chrome

<input type="datetime-local" value="2022-01-01 08:01:00">

displays a blank datetime input and submits an empty string if not updated

I’ll update if I find a good solution.

Update: This works in Firefox and Chrome:
forms.py:

widgets={
   'when':forms.DateTimeInput(
       format='%Y-%m-%dT%H:%M:%S',  
       attrs={'type':'datetime-local'} 
    ),
    ...
}

What Chrome was rejecting was having the value specified without the T between the date portion and the time portion. Django was producing the value without the T. By adding the format argument, I was able to make Django produce a default value that Chrome accepts.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.