views:

21

answers:

2

I have a Django form with a username and email field. I want to check the email isn't already in use by a user:

def clean_email(self):
    email = self.cleaned_data["email"]
    if User.objects.filter(email=email).count() != 0:
        raise forms.ValidationError(_("Email not available."))
    return email

This works, but raises some false negatives because the email might already be in the database for the user named in the form. I want to change to this:

def clean_email(self):
    email = self.cleaned_data["email"]
    username = self.cleaned_data["username"]
    if User.objects.filter(email=email,  username__ne=username).count() != 0:
        raise forms.ValidationError(_("Email not available."))
    return email

The Django docs say that all the validation for one field is done before moving onto the next field. If email is cleaned before username, then cleaned_data["username"] won't be available in clean_email. But the docs are unclear as to what order the fields are cleaned in. I declare username before email in the form, does that mean I'm safe in assuming that username is cleaned before email?

I could read the code, but I'm more interested in what the Django API is promising, and knowing that I'm safe even in future versions of Django.

+2  A: 

There's no promise that the fields are processed in any particular order. The official recommendation is that any validation that depends on more than one field should be done in the form's clean() method, rather than the field-specific clean_foo() methods.

Daniel Roseman
That's not correct. There is a promise on the processing order of the fields. It's just not kept well in all versions. Perhaps the newer Django versions do hold up to this promise but I haven't verified that.
WoLpH
+1  A: 

The Django docs claim that it's in order of the field definition.

But I've found that it doesn't always hold up to that promise. Source: http://docs.djangoproject.com/en/dev/ref/forms/validation/

These methods are run in the order given above, one field at a time. That is, for each field in the form (in the order they are declared in the form definition), the Field.clean() method (or its override) is run, then clean_(). Finally, once those two methods are run for every field, the Form.clean() method, or its override, is executed.

WoLpH
@WoLpH: that's the paragraph I read, and it doesn't claim the fields are process in order. "These methods are run in the order given above" refers to the bullet list of methods: to_python(), validate(), run_validators(), clean(), clean_<fieldname>(), form.clean().
Ned Batchelder
That's not true Ned Batchelder, look at this part: `for each field in the form (in the order they are declared in the form definition)`
WoLpH
Ah, I see, yes, sorry.
Ned Batchelder