2014-09-15

Using a datepicker in Django model form

If your front end framework (e.g. Bootstrap) has a datepicker CSS class that you would like to use in a Django model form, how can you do that?
It turns out we can add any attribute to a HTML input element in a Django model form via the formfield_callback defined in the model form. We can make use of this technique to add the datepicker class (an attribute) to a model DateField (an HTML input element).
The following is an example of adding the datepicker class to all the DateFields in a model form. You will also have to make sure the datepicker class definition is available, probably by including the front end framework files in the base template.
=== forms.py (model datefield) ===

from django.forms import ModelForm
from django.db import models
from .models import MyModel

def make_custom_datefield(f):
    # f is a model field
    # if f is a date field, add the datepicker class to it
    # return a form field
    formfield = f.formfield()
    if isinstance(f, models.DateField):
        formfield.widget.attrs.update({'class':'datePicker'})
    return formfield

class MyForm(ModelForm):
    formfield_callback = make_custom_datefield
    class Meta:
        model = MyModel

=== html rendered ===

<input class="datePicker" id="id_datefield" name="datefield" type="text" value="" />
How about adding the datepicker class to a form DateField (instead of a model DateField)? We can just add an attribute directly in the form DateField definition. The following is an example of it.
=== forms.py (form datefield) ===

class MyForm(ModelForm):
    somedate = forms.DateField(
                 widget=forms.TextInput(attrs={'class':'datePicker'}))
    class Meta:
        model = MyModel

EDITED 2015-07-07 If the form uses a custom widget, add a keyword argument to the formfield_callback function like below, otherwise you will have a "make_custom_datefield() got an unexpected keyword argument 'widget'" error.
def make_custom_datefield(f, **kwargs):
    formfield = f.formfield(**kwargs)
    if isinstance(f, models.DateField):
        formfield.widget.attrs.update({'class':'datePicker'})
    return formfield

No comments: