So after using Django on-and-off for close to 15 years, I recently learnt of a cool new (to me at least) trick. You can override the widget templates used to generate the field components for the generation of forms. These can be found here https://github.com/django/django/tree/main/django/forms/templates/django/forms/widgets
The biggest benefit to this, is not having to write custom forms, or widget over-rides in all of your Forms and ModelForms. Once you have changed the default widget template, all of your DateTimeFields will automatically use those settings.
Less code, less duplication.
Enabling the template engine
Update settings.py
INSTALLED_APPS = [
'blog.apps.BlogConfig',
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'django.forms', # <- add this app to installed apps
]
# Validate APP_DIRS and DIRS are configured
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [BASE_DIR / 'templates'],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
# Add this line to change the form renderer to TemplateSetting
FORM_RENDERER = 'django.forms.renderers.TemplatesSetting'
Create the override templates
From your project template directory, I'm using ./templates/
create the following directories
$ mkdir -p django/forms/widgets
so you should now have a set of directories that look like this.
├── templates
│ └── django
│ └── forms
│ └── widgets
To override the Django widgets we need to select the widget we wish to override, in this case we will be using DateTimeField
.
Look at the original source file for DateTime.html from the Django Repo.
datetime.html
{% include "django/forms/widgets/input.html" %}
We can see that datetime.html
inherits from the default input.html
.
input.html
<input
type="{{ widget.type }}"
name="{{ widget.name }}"
{% if widget.value != None %}
value="{{ widget.value|stringformat:'s' }}"
{% endif %}
{% include "django/forms/widgets/attrs.html" %}
>
We will use this as our basis for our new datetime.html
.
create a file ./django/forms/widgets/datetime.html
and add the following content.
Note that have changed the
type="{{ widget.type }}"
totype="datetime-local"
as defined here https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/datetime-local .
<input
type="datetime-local"
name="{{ widget.name }}"
{% if widget.value != None %}
value="{{ widget.value|stringformat:'s' }}"
{% endif %}
{% include "django/forms/widgets/attrs.html" %}
>
Now simply manage.py runserver
and you should see your browser now shows a date and time picker.
If you wish to configure a date picker, create a date.html
file and set the type to type="date"
.
To configure a time picker, create a time.html
file and set the type to type="time"
.
Congrats!
Top comments (0)