Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Making Django forms.DateField show use local date format

I'm trying to find an easy way to build forms which show dates in the Australian format (dd/mm/yyyy). This was the only way I could find to do it. It seems like there should be a better solution.

Things to note:

  • Created a new widget which renders date value in dd/mm/yyyy format
  • Created new date field to prepend the locate date format string to the list of values it tries to use

I imagine the ideal solution would be a datefield which automatically localised but that didn't work for me (strftime didn't seem to be unicode friendly but I didn't try very hard)

Am I missing something? Is there a more elegant solution? Is this a robust approach?

from models import *
from django import forms
import datetime

class MyDateWidget(forms.TextInput):

    def render(self, name, value, attrs=None):

            if isinstance(value, datetime.date):
                    value=value.strftime("%d/%m/%Y")

            return super(MyDateWidget, self).render(name, value, attrs)


class MyDateField(forms.DateField):

    widget = MyDateWidget

    def __init__(self, *args, **kwargs):
            super(MyDateField, self).__init__(*args, **kwargs)
            self.input_formats = ("%d/%m/%Y",)+(self.input_formats)


class ExampleForm(ModelForm):
    class Meta: 
            model=MyModel
            fields=('name', 'date_of_birth')

    date_of_birth = MyDateField()
like image 707
olivergeorge Avatar asked Sep 21 '09 08:09

olivergeorge


People also ask

How do I change the date format in Django?

Python django format date dd/mm/yyyy And, because the format is dd/mm/yyyy, we must use a slash to separate the date, month and year. To separate the day from the month and the month from the year in a date notation we use DateSeparator.

What is default date format in Django?

django default date to be in format %d-%m-%Y.

How do I change the date on a form?

Press Control+1 or Command+1. In the Format Cells box, click the Number tab. In the Category list, click Date, and then choose a date format you want in Type. You can adjust this format in the last step below.


1 Answers

Granted, I'm not a django/python Jedi, but...

I don't think there is anything wrong with your approach. It is a clean read.

You might not need to create your own widget just to render the date in the proper format on the first form display. Just use the format parameter for the DateInput widget and you should be OK. So in your MyDateField class I would just do:

class MyDateField(forms.DateField):

    widget = forms.DateInput(format="%d/%m/%Y")

    def __init__(self, *args, **kwargs):
        super(MyDateField, self).__init__(*args, **kwargs)
        self.input_formats = ("%d/%m/%Y",)+(self.input_formats)

You could use formfield_callback (See the accepted answer for this distantly related question), meaning:

def customize_fields(f):
    if isinstance(f, DateTimeField):
        datetime_field=forms.DateTimeField(widget=
            forms.DateInput(format='%d/%m/%Y %h:%i'))
        date_field.input_formats = ("%d/%m/%Y %h:%i",)+
            (date_field.input_formats)
        return datetime_field
    elif isinstance(f, DateField):
        date_field=forms.DateField(widget=
            forms.DateInput(format='%d/%m/%Y'))
        date_field.input_formats = ("%d/%m/%Y",)+
            (date_field.input_formats)
        return date_field
    else:
        return f.formfield()

class MyModelForm(forms.ModelForm):
    formfield_callback = customize_fields

    class Meta:
        model = ...

Doing that completely eliminates the need for your MyDateField class, but might introduce - if you want every single form class to call customize_fields - the need for a ModelForm descendent, implementing formfield_callback=customize_fields as the new base for all your form classes.

My problem with using the formfield_callback mechanism is two-fold:

  1. It is less readable and relies in knowledge of the inner workings of ModelForms. I can't find actual documentation on formfield_callback anywhere...

  2. If you ever need to redefine a model field in a ModelForm, say to make the field not required for that particular instance of the form, like so:

       class MyModelForm(forms.ModelForm):
           formfield_callback = customize_fields
           foo = forms.DateField(required=false)
    
           class Meta:
               model = Bar
    

    you are overwriting the form field returned by customize_fields, hence completely losing the customization.

I think your approach is more readable.

like image 130
cethegeek Avatar answered Oct 13 '22 07:10

cethegeek