Making Django forms.DateField show use local date format

前端 未结 4 660
死守一世寂寞
死守一世寂寞 2020-12-29 14:35

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 sho

相关标签:
4条回答
  • 2020-12-29 14:56

    All of the custom widget stuff can be bypassed.

    Here's an excerpt from django/forms/widgets.py:

    class DateInput(TextInput):
        def __init__(self, attrs=None, format=None):
            super(DateInput, self).__init__(attrs)
            if format:
                self.format = format
                self.manual_format = True
            else:
                self.format = formats.get_format('DATE_INPUT_FORMATS')[0]
                self.manual_format = False
    

    You'll notice that the format of the widget is set using the format module. The format module is selected depending on the locale. If you're browsing from the US, Django will, by default, select django.conf.formats.locale.en.formats.py. Here you will find the default format:

    DATE_INPUT_FORMATS = (
        '%Y-%m-%d', '%m/%d/%Y', '%m/%d/%y', # '2006-10-25', '10/25/2006', '10/25/06'
        # '%b %d %Y', '%b %d, %Y',            # 'Oct 25 2006', 'Oct 25, 2006'
        # '%d %b %Y', '%d %b, %Y',            # '25 Oct 2006', '25 Oct, 2006'
        # '%B %d %Y', '%B %d, %Y',            # 'October 25 2006', 'October 25, 2006'
        # '%d %B %Y', '%d %B, %Y',            # '25 October 2006', '25 October, 2006'
    )
    

    As you can see in the first code block, Django selects the first of these. The thorough approach to changing the format is to create your own format module, overriding Django's default for the locale in question. For that, look into FORMAT_MODULE_PATH. If all you're trying to do is override the default date format, I say save yourself some time and monkey patch. I added this to my settings file and everything appears to be working splendidly with my preferred default format:

    DATE_INPUT_FORMATS = ('%m/%d/%Y', '%m/%d/%y', '%Y-%m-%d',
                          '%b %d %Y', '%b %d, %Y', '%d %b %Y',
                          '%d %b, %Y', '%B %d %Y', '%B %d, %Y',
                          '%d %B %Y', '%d %B, %Y')
    from django.conf.locale.en import formats
    formats.DATE_INPUT_FORMATS = DATE_INPUT_FORMATS
    
    0 讨论(0)
  • 2020-12-29 15:01

    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.

    0 讨论(0)
  • 2020-12-29 15:01

    I've used this simple approach before: just set the 'format' attribute of the DateField.widget in the init of the Form:

        class ExampleForm(ModelForm):
    
            class Meta:
                model = MyModel
    
            def __init__(self, *args, **kwargs):
                super(ModelForm, self).__init__(*args, **kwargs)
                self.fields['date_of_birth'].widget.format = '%d/%m/%Y'
    
                # at the same time, set the input format on the date field like you want it:
                self.fields['date_of_birth'].input_formats = ['%d/%m/%Y']
    
    0 讨论(0)
  • 2020-12-29 15:07

    In my form I'me using:

    def today():
        from datetime import date
        return date.today().strftime("%d.%m.%Y")
    
    when = models.DateField(u'Когда', default=today)
    
    0 讨论(0)
提交回复
热议问题