~blog~

A simple site-wide, per-user, date format validation system

It is important to be aware that dates are spelled differently in different countries (e.g. dd/mm/yyyy in Australia or mm/dd/yyyy in the US). This is why it is a good idea to let the user select their preferred date format and store it into their user profile. For example, you may store the values "%d/%m/%Y" or "%m/%d/%Y" in that user's profile. That way, you may display dates in the format chosen by the user throughout the site.

Now, if the site contains many forms with date fields (say, for example, you're building a calendar application), it can be a bit repetitive and annoying to check and assign the date format for every form in every view. To go around that, I came up with a simple trick. It all happens in the following class:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
class FormWithFormattedDates(forms.ModelForm):
    def __init__(self, *args, **kwargs):
        date_format = None
        if 'date_format' in kwargs:
            date_format = kwargs['date_format']
            del kwargs['date_format'] # The ModelForm's __init__ method doesn't expect to receive that argument, so take it out.
        super(FormWithFormattedDates, self).__init__(*args, **kwargs)
        if date_format is not None:
            for (field_name, field) in self.fields.items():
                if isinstance(field, forms.fields.DateField):
                    field.input_format = [date_format]
                    field.widget = forms.widgets.DateTimeInput(format=date_format)

What this class does is explore what's in the form, and make sure that all date fields will display and validate with the given date format.

Then, all you need to do is to make all your forms that contain date fields inherit from the above class. For example:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
# Model
class Event(models.Model):
    title = models.CharField(max_length=100)
    start_date = models.DateField()
    end_date = models.DateField()

#Form
class EventForm(FormWithFormattedDates):
    class Meta:
        model = Event

The next step is then in the view. When you instantiate the form, just pass it the user's preferred format as parameter:

1
2
3
4
5
def add_new_event(request):
    if request.method == 'POST':
        form = EventForm(data=request.POST, date_format=request.user.get_profile().date_format)
        if form.is_valid():
            ...

All the validation logic is taken care of by the FormWithFormattedDates class. This allows to both keep the views' code very simple, and also to not have to worry about per-user validation as it all happens automatically.

Update: I could add that you could use the same approach to let the user select their preferred time format (e.g. "1pm" or "13:00"), or, in fact, with any kind of validation that needs to be operated on a large number of forms in your site and where that validation also depends on the user's preferences.

Comments

# Rock 30 Jul 2008, 8:31 p.m.

Very nice. Do you happen to have a template tag along these same lines to share as well?

# Julien Phalip 04 Aug 2008, 9:30 p.m.

@Rock

I'm not sure what you mean concerning the template tag. Could you explain what you would like to achieve?

# spool 11 Aug 2008, 4:16 a.m.

This could save me a great deal of frustration. Do you know how to achieve the same effect in the auto-generated admin? So that ever datefield appears in the British format rather than the Y-m-d format and validates properly?

Thanks very much

# Julien Phalip 11 Aug 2008, 9:40 a.m.

@spool

If you want the date format to be the same for all users, you should use the DATE_FORMAT setting [1]. I believe it's also possible to customise the admin so you can have a user-configurable option too. I'll look it up and post a follow-up soon.

[1] http://www.djangoproject.com/document...

# spool 16 Aug 2008, 3:26 p.m.

Hey Julien,

thanks for the reply. Unfortunately, that doesn't actually change the input validation, only how dates are displayed on the changes list (for example). I think I have to write a custom widget. I'll let you know how that goes.

# Goferblogger 02 Feb 2009, 9:02 p.m.

https://weblion.psu.edu/trac/weblion/... - buy cheap online tramadol

Post a comment