2

I want to allow the entry of a date without a year into a DateField to mean the actual year. Like "10.6." should mean 10 June 2021, since it's 2021 at the time of writing. The following DATE_INPUT_FORMATS didn't cut it:

DATE_INPUT_FORMATS = ('%d.%m.%y', '%d.%m.%Y', '%Y-%m-%d', '%d.%m.')

This does allow such input, but the year will be 10 June 0000; not what I aimed for.

Any advice?

cxxl
  • 4,939
  • 3
  • 31
  • 52

2 Answers2

2

This does allow such input, but the year will be 10 June 0000.

as far as I know it will be June 10, 1900, but that of course does not matter much.

You can implement a clean_fieldname in your Form, for example:

from django import forms from django.utils.timezone import now

class MyForm(forms.Form):
    day = forms.DateField()

    def clean_day(self):
        day = self.cleaned_data['day']
        if day.year == 1900:
            day = day.replace(year=now().year)
        return day

In the clean method we thus check if the year is 1900, and if that is the case, we replace it with the current year.

Of course if the user enters 10.6.1900, this will also be replaced by June 10, 2021. We thus can not know if it was parsed by the '%d.%m' pattern, or the %d.%m.%y pattern.

Willem Van Onsem
  • 443,496
  • 30
  • 428
  • 555
1

A somewhat more robust solution that would still accept the year 1900 as a valid input would be to override the forms DateField itself. Although this comes with the caveat that you cannot easily integrate with the input formats that we can set in the settings and hence this is not very suitable if you want format localization:

import datetime

from django import forms
from django.core.exceptions import ValidationError


class YearOptionalDateField(forms.DateField):
    yearless_formats = ['%d.%m.']

    def to_python(self, value):
        try:
            return super().to_python(value)
        except ValidationError:
            value = value.strip()
            for format in self.yearless_formats:
                try:
                    date = self.strptime(value, format)
                    return date.replace(year=datetime.datetime.now().year)
                except (ValueError, TypeError):
                    continue
            raise


class YourForm(forms.Form):
    date = YearOptionalDateField()


# Test
form = YourForm({'date': '10.6.'})
print(form.is_valid())  # True
print(form.cleaned_data['date'])  # 2021-06-10

Note: Remove '%d.%m.' and any similar formats you may have from DATE_INPUT_FORMATS for this to work.

Abdul Aziz Barkat
  • 19,475
  • 3
  • 20
  • 33