Django form.instance.field displaying incorrect datetime value on HTML template despite having the correct value at hand
I'm running Django 4.1
, and the view that serves the template is a FormView
-child.
To start off with, here's the canonical answer as to what the correct value is, taken directly from the database:
In [6]: DCF.objects.last().appreciation_date
Out[6]: datetime.date(2023, 1, 24)
The first HTML template invocation of that same field:
<h5>Title: {{ form.instance.appreciation_date }}</h5>
And the result is as expected:
About 30 lines of code below (none of which do anything particularly functional, it's just a boatload of div
declarations for CSS and styling), inside a <form>
, on a modal:
<div class="mb-3">
<label for="{{ form.appreciation_date.id_for_label }}">Date</label>
<input class="form-control datepicker" placeholder="Please select date" type="text" onfocus="focused(this)" onfocusout="defocused(this)" name="{{ form.appreciation_date.name }}" value="{{ form.instance.appreciation_date }}">
</div>
And now, prepare for the result - which also highlights the question I am about to get to:
What in Django's ghost in the shell is going on? How did 2023-01-24
become 2023-01-01
for no apparent reason? Or said differently, why and how can the same context invocation have two different values in the same render of the same template?
I would very much like for the second invocation to show the correct value - meaning the value that is both in the database, and presumably also in the context (since it's showing the correct value before the modal is opened).
Things that do not work:
- Reload (F5)
- Force reload (Shift+F5)
- Relaunching the server
- Force updating the database value for that field to a different date
To make matters worse, the value apparently is correct even when it's not - or so the developer console says. The date is different from 2023-01-24
because this screenshot was taken after I updated the date manually, as mentioned in the list of things that did not work:
In [7]: DCF.objects.last().appreciation_date
Out[7]: datetime.date(2023, 1, 25)
So at the end of this all, what is happening that makes ... something, whether it's Django or something else, render the value of 2023-01-24
as 2023-01-01
in one instance but not in the other?
I had basically spent an hour writing this question before I stumbled upon what I almost instantly realized would lead to the solution at the end of the post, so given the effort spent I'll post and self-answer.
It would appear that Django picked a string format when it came time to transmit the datetime
object to the browser, and when trying to populate the date-picker
element with this predetermined value, we discover that the browser doesn't understand dates in the MMM-DD-YYYY
format.
Changing the problematic invocation thusly solved the issue:
value="{{ form.instance.appreciation_date|date:'Y-m-d'}}"
The explanation of why this work is roundaboutly as follows:
Tacking on |date:'Y-m-d'
uses Django's built-in date filter to format the datetime
object before any values are actually rendered into the HTML file.