Django: Flexible date form fields accepting (almost) any input

At critify, we do a lot of copy & paste. Sometimes, that means copy & pasting a date from another site into a Django DateTimeField on our site. This can be tedious, because Django only supports a fixed number of strict input formats, while the actual input can at times be something quite freeform. So I decided that what was needed were date form fields that would make a good attempt at parsing the input.

Here’s what you need:

  • python-dateutil, which provides the parser.
  • This file, which implements DateTimeField and DateField form field classes which use python-dateutil to process the input.

With that available, the actual code is quite simple:

from djutils.forms.fields import formfield_callback

class YourForm(ModelForm):
    formfield_callback = formfield_callback
    class Meta:
        model = YourModel

The formfield_callback will ensure that for every DateField or DateTimeField that your model has, the appropriate form field with dateutil-parsing support will be generated.

Of course, you can use these fields manually as well:

from django import forms
from djutils.forms.fields import DateField

class MyForm(forms.Form):
    std_date = forms.DateField() # < - Uses the standard DateField
    parsed_date = DateField()  # <- Uses the custom DateField

This should work well enough; we can now put something like 8th of January into the form, and it’ll be parsed into the correct date.

“8th of January”? My site is in German! Fortunately, while not supporting it out of the box, python-dateutil is flexible enough to allow for internationalization as well. You need to get:

  • Yet another file, which adds support for German date strings to python-dateutil (i.e. “Janauar”, “Montag”, ….). If you need to support a different language, you can use that file as a template.

The way internationalization is done with python-dateutil is that you implement a parserinfo class for a given language. We need to tell our custom form fields to use the German parserinfo provided by the file above:

from djutils.forms.fields import get_formfield_for
from pyutils.date import GermanParserInfo

class YourForm(ModelForm):
    def formfield_callback(field):
         # If it's a date-related field, get one of our custom form fields 
         result = get_formfield_for(field, parserinfo=GermanParserInfo()) 
         # Otherwise, use the default form field.
         return result or field.formfield()
    class Meta:
        model = YourModel

That’s basically it. You might want to create a base form class that you can inherit from for DRY purposes.

By the way, my module containing the German parser info also has a MultiParserInfo helper that may be useful to some:

parserinfo=MultiParserInfo(parsers=[GermanParserInfo()])

This will give you a parser that supports both German date names, and the original English date names as a fallback. If you need to support even more languages, you could too:

parserinfo=MultiParserInfo(parsers=[GermanParserInfo(), FrenchParserInfo()])

2 thoughts on “Django: Flexible date form fields accepting (almost) any input

  1. You sir, rock. This has saved me a *major* piece of my sanity. I’m implementing this in a project for our university’s equipment checkout tracking web application.

    Check your email… as a token of my appreciation, I’m sending you some “beer” from my part of the world. It doesn’t quite beat some of the German ones I’ve had, but it ranks up there. 🙂

    Like

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