#33142: Form clean method called after validation field clean method fails
------------------------------------------+------------------------
Reporter: David Babalola | Owner: nobody
Type: Bug | Status: new
Component: Forms | Version: 3.2
Severity: Normal | Keywords:
Triage Stage: Unreviewed | Has patch: 0
Needs documentation: 0 | Needs tests: 0
Patch needs improvement: 0 | Easy pickings: 0
UI/UX: 0 |
------------------------------------------+------------------------
I am working on a Django project wherein the validation depends on the
field `clean` method being run first.
According to
[https://docs.djangoproject.com/en/3.2/ref/forms/validation/#validating-
fields-with-clean], each of the fields clean method are called first, then
the form's `clean` method is called.
I found out that after a field's clean method is called, and validation
fails, that field's `clean` method returns an empty/None value for that
field. In essence, it still calls the form's `clean` method after the
validation in any of the field fails.
The validation in the form's `clean` method is dependent on the values
from those fields. If those values are `None`, or empty my validation
would produce an error.
To reproduce this, you can create a form such as this.
{{{
class ActionForm(forms.ModelForm):
phone_number = forms.CharField(required=False)
code = forms.CharField(max_length=10, required=False)
name = forms.CharField(max_length=100)
class Meta:
model = Withdrawal
fields = ['name', 'code', 'phone_number']
def clean(self):
# Ensure you can't withdraw more than your balance
cleaned_data = super().clean()
phone_number = cleaned_data.get("phone_number")
code = cleaned_data.get("code")
if phone_number == '' and code == '':
# Both code and phone number fields are empty: Raise
Validation error
raise forms.ValidationError("You must enter either the Phone
number or the code.")
user = None
if phone_number == '' or phone_number is None:
# Use user code to get user object
user = User.objects.get(code=code)
else:
# Use user phone number to get user object
user = User.objects.get(phone_number=phone_number)
def clean_phone_number(self):
# Check if User with phone number exists
phone_number = self.cleaned_data.get('phone_number')
if phone_number == '':
# If User phone number is empty, don't validate it
return phone_number
user = User.objects.filter(phone_number=phone_number)
if not user.exists():
raise forms.ValidationError('User with this Phone Number does
not exist.')
return phone_number
def clean_code(self):
# Check if user with user code exists
code = self.cleaned_data.get('code')
if code == '':
# If User code is empty, don't validate it
return code
user = User.objects.filter(code=code)
if not user.exists():
raise forms.ValidationError('User with this user code does not
exist.')
return code
}}}
In the above code, if a code or phone number is entered that is not in the
database, the lines `user = User.objects.get(code=code)` and `user =
User.objects.get(phone_number=phone_number)` would generate the following
error:
`accounts.models.User.DoesNotExist: User matching query does not exist.`
Furthermore, I printed out the value of the code and phone_number inside
the form's `clean()` method. I found out that when invalid values are
entered, it prints out empty strings or None. Hence my conclusion that
Django calls the form's `clean()` method even after validation of a
specific field fails.
--
Ticket URL: <https://code.djangoproject.com/ticket/33142>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.
--
You received this message because you are subscribed to the Google Groups
"Django updates" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To view this discussion on the web visit
https://groups.google.com/d/msgid/django-updates/053.1455a3f70cd8ecca5cb27aff19adc0d0%40djangoproject.com.