#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.

Reply via email to