ModelForm always calls Model's clean method

287 views
Skip to first unread message

ak37

unread,
May 19, 2010, 1:12:23 AM5/19/10
to Django users
Hi,

I just tried the new Model Validation feature in Django 1.2 and I
found out that ModelForm always calls the Model's clean method even
when the form validation has errors. This causes problems when the
model has a foreign key, and the value is validated in the clean
method. Consider this example:

class Flight(models.Model):
aircraft = models.ForeignKey(Aircraft)
departure = models.ForeignKey(Departure)
arrival = models.ForeignKey(Arrival)

def clean(self):
# There can never be flights departing and arriving to the
same place
if self.departure == self.arrival:
raise ValidationError("Departure is the same as Arrival")

class FligthForm(forms.ModelForm):
class Meta:
model = Flight

If the form is submitted with empty values, I will get a DoesNotExist
exception when trying to access the self.departure/self.arrival
attribute in the clean method. Is this by design? If it is then what
is the recommended practice to implement the Model's clean method?

Regards,
Rendy Anthony (ak37)

--
You received this message because you are subscribed to the Google Groups "Django users" group.
To post to this group, send email to django...@googlegroups.com.
To unsubscribe from this group, send email to django-users...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/django-users?hl=en.

Karen Tracey

unread,
May 19, 2010, 9:16:33 AM5/19/10
to django...@googlegroups.com
On Wed, May 19, 2010 at 1:12 AM, ak37 <rendy....@gmail.com> wrote:
I just tried the new Model Validation feature in Django 1.2 and I
found out that ModelForm always calls the Model's clean method even
when the form validation has errors. This causes problems when the
model has a foreign key, and the value is validated in the clean
method. Consider this example:

class Flight(models.Model):
   aircraft = models.ForeignKey(Aircraft)
   departure = models.ForeignKey(Departure)
   arrival = models.ForeignKey(Arrival)

   def clean(self):
       # There can never be flights departing and arriving to the
same place
       if self.departure == self.arrival:
           raise ValidationError("Departure is the same as Arrival")

class FligthForm(forms.ModelForm):
   class Meta:
       model = Flight

If the form is submitted with empty values, I will get a DoesNotExist
exception when trying to access the self.departure/self.arrival
attribute in the clean method. Is this by design? If it is then what
is the recommended practice to implement the Model's clean method?
 

Calling the model clean() even though validation errors have already been noted is consistent with the way form validation is done: the form-wide clean() is called even when validation errors have been raised for individual fields. It's up to the form-wide clean() to make sure the values it wants to work with survived the earlier cleaning attempts; this is noted for example here: http://docs.djangoproject.com/en/dev/ref/forms/validation/#cleaning-and-validating-fields-that-depend-on-each-other. Similarly a model clean() method must be aware that the values it has may not be valid per earlier validation that has been run.

In this specific case one way to deal with the issue would be to use a try/except block and catch the DoesNotExist. If one is raised, you may assume that that error has already been noted by the form cleaning, and just ignore it.

(I am a little confused by your model definition though -- you have departure and arrival defined as ForeignKeys to different models, so I don't see how they would ever compare as equal, unless your actual code is checking some attribute on each rather then equality of the foreign key values themselves?)

Karen
--
http://tracey.org/kmt/

Rendy Anthony

unread,
May 26, 2010, 1:02:39 PM5/26/10
to django...@googlegroups.com
My mistake in the model definition. They are supposed to be foreign keys to the same model.

Thank you for the explanation. I was expecting something like the errors variable like in a Form. Unfortunately there is no equivalent "error" variable in the model validation. Here is what I can do in forms:

class MyForm(forms.Form):
    def clean(self):
        if self.errors:
            return # Skip validation if there are existing errors

        if self.cleaned_data['departure'] == self.cleaned_data['arrival']:
            raise ValidationError("Can't be the same")

I think the documentation should make it clear that the DoesNotExist exception might be raised in the clean method when trying to access a foreign key.

Regards,
Rendy Anthony
Reply all
Reply to author
Forward
0 new messages