[Django] #33142: Form clean method called after validation field clean method fails

2 views
Skip to first unread message

Django

unread,
Sep 24, 2021, 4:05:57 PM9/24/21
to django-...@googlegroups.com
#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.

Django

unread,
Sep 24, 2021, 9:27:42 PM9/24/21
to django-...@googlegroups.com
#33142: Form clean method called after validation field clean method fails
--------------------------------+--------------------------------------

Reporter: David Babalola | Owner: nobody
Type: Bug | Status: closed
Component: Forms | Version: 3.2
Severity: Normal | Resolution: invalid

Keywords: | Triage Stage: Unreviewed
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
--------------------------------+--------------------------------------
Changes (by Tim Graham):

* status: new => closed
* resolution: => invalid


Comment:

As far as I can tell, you've described behavior that's documented earlier
on the page you linked to: "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_<fieldname>()`. Finally, once
those two methods are run for every field, the `Form.clean()` method, or
its override, is executed whether or not the previous methods have raised
errors."

--
Ticket URL: <https://code.djangoproject.com/ticket/33142#comment:1>

Reply all
Reply to author
Forward
0 new messages