DEV Community

Benjamin.dog
Benjamin.dog

Posted on

How to configure a date and datetime picker in Django using a global widget template override

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'
Enter fullscreen mode Exit fullscreen mode

Create the override templates

From your project template directory, I'm using ./templates/ create the following directories

$ mkdir -p django/forms/widgets
Enter fullscreen mode Exit fullscreen mode

so you should now have a set of directories that look like this.

├── templates
│  └── django
│     └── forms
│        └── widgets
Enter fullscreen mode Exit fullscreen mode

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" %}
Enter fullscreen mode Exit fullscreen mode

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" %}
>
Enter fullscreen mode Exit fullscreen mode

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 }}" to type="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" %}
>
Enter fullscreen mode Exit fullscreen mode

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!

Discussion (0)