user1011444
user1011444

Reputation: 1399

Why does Django throw a KeyError on this form validation?

Here's the code:

...

class Meta:
    model = Card

def clean_video_url(self):
    video_url = self.cleaned_data['video_url']
    if video_url != '' and len(video_url) != YOUTUBE_VIDEO_URL_LENGTH:
        pos = string.find(video_url, YOUTUBE_VIDEO_URL_IDENTIFIER)
        identifier_length = len(YOUTUBE_VIDEO_URL_IDENTIFIER)
        if pos == -1:
            raise forms.ValidationError(_('youtube-url-not-valid'))
        video_url = video_url[pos+identifier_length:pos+identifier_length+YOUTUBE_VIDEO_URL_LENGTH]
    return video_url

...

def clean(self):
    video_url = self.cleaned_data['video_url']
    field1 = self.cleaned_data['field1']
    if video_url == '' and field1 == '':
        raise forms.ValidationError(_('must-fill-video-url-or-front'))
    return self.cleaned_data

The most disturbing thing is that it works (submits and persists in the database) in almost all situations. It doesn't work when I write dummy text like 'aeuchah' in the video_url field, but instead it throws:

Exception Type: KeyError
Exception Value:    
'video_url'

I re-read my clean_video_url method and went to see what the variables were with a debug tool like pdb.set_trace, but I can't find the problem.

UPDATE: As Marius Grigaitis and Davide R. said, the clean method is called after all the individual field methods are done. clean_video_url raised a ValidationError and returned nothing, so the clean method found nothing to work with and raised a KeyError.

Upvotes: 3

Views: 1262

Answers (1)

Marius Grigaitis
Marius Grigaitis

Reputation: 2520

You should always check that key exists in cleaned_data before using it in clean() method. You're not guaranteed that value is present in cleaned_data array if previous validations has not passed.

Documentation: https://docs.djangoproject.com/en/dev/ref/forms/validation/#cleaning-and-validating-fields-that-depend-on-each-other

By the time the form’s clean() method is called, all the individual field clean methods will have been run (the previous two sections), so self.cleaned_data will be populated with any data that has survived so far. So you also need to remember to allow for the fact that the fields you are wanting to validate might not have survived the initial individual field checks.

Upvotes: 4

Related Questions