Search code examples
djangodatetimedjango-modelsdjango-formsdate-format

Django DateField format impossible to validate and save to model


Old issue, I know. But I still could not find a working solution so I may have missed something obvious. Here is my form

class AddPatientForm(forms.Form):
    last_name = forms.CharField(label='Nom', max_length=40)
    first_name = forms.CharField(label='Prénom', max_length=40)
    birthday = forms.DateField(label='date de naissance',
         widget=forms.DateInput(format='%d/%m/%Y',attrs={'placeholder': '31/03/1989'}),
         input_formats=['%d/%m/%Y',])

It follows this format convention and has to do so. Here is my model:

class Patients(models.Model):
    first_name = models.CharField(max_length=40)
    last_name = models.CharField(max_length=40)
    birth_date = models.DateField()
    inscription = models.DateTimeField(auto_now_add=True)

And here is what I tried in setting.py to get rid of the issue

DATE_FORMAT = "d-m-Y"
DATE_INPUT_FORMATS = ['%d-%m-%Y']
USE_L10N = False

Despite of this, I still got the same issue:

form = AddPatientForm(request.POST)
    if form.is_valid():
        form.clean()
        d = Patients(first_name= form["first_name"].value(), 
            last_name= form["last_name"].value(),
            birth_date= form["birthday"].value())
        d.save()
>>>>["Le format de date de la valeur «\xa027/10/1987\xa0» n'est pas valide. Le format correct est AAAA-MM-JJ."]

[disclaimer] I am not looking to override the model format convention and I know that the question of how dates "are really stored in db" is irrelevant (different from one DBMS to an other; django models are agnostic about it). But that's such a pin in the *** to struggle with such a simple task. Why can't I:

  • use different format for forms and models?
  • override somehow this parameter?

Isn't the very fact of being a DateField with an explicit format provided with explicit parameters sufficient for the validator to understand what's what? What am I missing?

Any insight is welcome


Solution

  • The caracter \xa0 is related to iso8859-1 encodage. Here is an example:

    >>> a = b'\xa027/10/1987\xa0'
    >>> a.decode('iso8859-1').strip()
    '27/10/1987'
    

    So, in your question, if birth_date= form["birthday"].value() is a bytes object, you need first to decode it in a regular string with valid date format for further manipulaiton:

    birth_date = form["birthday"].value().decode('iso8859-1')
    

    Otherwise if the type of birth_date is a string, you can easly do:

    birth_date = form["birthday"].value().replace(u'\xa0', u'')
    

    Then, in order to store the date in your Database you need a valid datetime object. You can convert your string to a valid Python datetime object like this example:

    >>> from datetime import datetime
    >>> datetime.strptime('27/10/1987', '%d/%m/%Y')
    datetime.datetime(1987, 10, 27, 0, 0)
    

    Bonus: if you need an aware datetime object, think of using pytz module.