e2718281
e2718281

Reputation: 35

Django ValidationError not being raised; key not present in cleaned_data

I have the following form fields on a ModelForm subclass:

forms.py

class ProjectUpdateForm(ModelForm):

    start_date = DateField(...)
    due_date = DateField(label="Due Date",
                         required=True,
                         widget=CustomDatePicker(),
                         validators=[validate_not_past])

    def clean(self):
        super().clean()    # Problem: this isn't this raising a ValidationError...
        start_date = self.cleaned_data.get('start_date')
        due_date = self.cleaned_data.get('due_date')
        if start_date > due_date:          # ...instead getting a TypeError from this line!
            raise ValidationError("Project Start Date cannot be after Project End Date")

validators.py

def validate_not_past(value):
    today = datetime.date.today()
    if value and value < today:
        raise ValidationError('This date cannot be in the past.', code='invalid')

Anytime that I enter a date in the past, the applications throws a TypeError: '>' not supported between instances of 'datetime.date' and 'NoneType' (see comments above for clarity).

After attempting to troubleshoot, the POST data comes in fine from the form. The problem occurs because run_validators() is raising the ValidationError triggered by the validate_not_past, validator (above) as expected. However, rather than raising the ValidationError, the self.cleaned_data dictionary just doesn't get a due_date key.

I can't figure out why I'm not getting a ValidationError raised. I can't find code elsewhere that catches it.

Thanks in advance.

Upvotes: 0

Views: 47

Answers (1)

Sanyam Khurana
Sanyam Khurana

Reputation: 1421

The clean_method can ideally optionally return a dictionary (recommended) to return the cleaned_data. If you do this and are doing inheritance in Forms, you'll not face any errors. Currently, your ProjectUpdateForm is not utilizing it correctly to call the clean() method on the super-class. Your code will be fixed if you call it correctly like this:

class ProjectUpdateForm(ModelForm):

    start_date = DateField(...)
    due_date = DateField(label="Due Date",
                         required=True,
                         widget=CustomDatePicker(),
                         validators=[validate_not_past])

    def clean(self):
        cleaned_data = super().clean()
        start_date = cleaned_data.get('start_date')
        due_date = cleaned_data.get('due_date')
        if start_date and due_date and start_date > due_date:
            raise ValidationError("Project Start Date cannot be after Project End Date")
        return cleaned_data

Note here that I'm also checking start_date and due_date are not None before doing the comparison between them. It wasn't evident from your code if the start_date is also mandatory, so I added this additional check.

Finally, I'm also returning cleaned_data which is optional but recommended, since then it enables this form to be inherited in other forms without any worries of correctly propagating errors from the super-class forms.

Upvotes: 0

Related Questions