Saturday, February 27, 2010

Custom Date Formats in the Django Admin

For better or for worse, subclassing Django components to add custom functionality is a common technique.  The workflow usually goes something like this:
  1. Subclass a django component
  2. Override a specific method
  3. Set some custom configuration options in the method
  4. Call super() 
For our Django 1.1 app, we needed to customize the behavior of a DateField so it would accept dates entered in the standard US format, MM-DD-YYYY, instead of the default behavior, YYYY-MM-DD.  We'll create a new field called USADateField.

First, let's add a new module to our app,

In, subclass the Datefield form, adding the MM-DD-YYY format to the tuple of default formats:

class USADateFormField(forms.DateField):
    def __init__(self, *args, **kwargs):
        kwargs.update({'input_formats': ("%m-%d-%Y",)+DEFAULT_DATE_INPUT_FORMATS})
        super(USADateFormField, self).__init__(*args, **kwargs)

Then, subclass the django model DateField to use the new USADateFieldForm:

class USADateField(models.DateField):
    def formfield(self, **kwargs):
        kwargs.update({'form_class': USADateFormField})
        return super(USADateField, self).formfield(**kwargs)

When you're done, your new module will look like this:

Finally, import fields in your module and use it!  Your model might look something like this:

class Appointment(models.Model):
    scheduled_date = USADateField(blank=True)

I like approaches like this, which push logic back into the models.  The functionality would be tougher to test and maintain if we wrote custom front-end code for the field.

1 comment:

Unknown said...

I've tried your source but it gave this error;

Django Version: 1.3
Exception Type: TypeError
Exception Value:

can only concatenate tuple (not "__proxy__") to tuple

Exception Location: G:\transporte\..\transporte\frete\ in __init__, line 10