Reputation: 11426
After checking my form is valid I perform additional validation:
def reset_passwd(req):
if req.method == 'POST':
form = ResetPasswdForm(req.POST)
if form.is_valid():
# extract data
passwd1 = form.cleaned_data['passwd1']
passwd2 = form.cleaned_data['passwd2']
# validate passwd
if passwd1 != passwd2:
raise forms.ValidationError('passwords are not the same', 'passwd_mismatch')
# do stuff...
return HttpResponseRedirect('/success')
else:
form = ResetPasswdForm(req.POST)
return render(req, 'reset_passwd_form.html', {'form': form})
Problem is raising a ValidationError
which is an Exception
of course breaks execution of the view function so no response is returned!
How is one suppose to return their bound form showing validation errors for validation not performed by form.is_valid()
?
(The confusing thing is the django documentation say form.is_valid()
throws ValidtionError
s if the form is invalid, however it must handel them as debugging it execution continues when is_valid()
is false.)
Upvotes: 1
Views: 10450
Reputation: 135
You need to override the is_valid() method, call the super is_valid() first ( return false if it returns false ), and then handle your error case.
If you use clean() instead you won't benefit for things such as "required=True" in your other fields and will need to check everything manually. super().clean() just ... does not check for it afaik, and it could give you KeyError when accessing cleaned_data['passwd1'] unless checking it yourself.
class MyResetPasswdForm(forms.Form):
passwd1 = forms.CharField(widget=forms.PasswordInput, required=True)
passwd2 = forms.CharField(widget=forms.PasswordInput, required=True)
def is_valid(self):
valid = super(MyResetPasswdForm).is_valid()
if not valid:
return valid
if self.cleaned_data.get("passwd1") != self.cleaned_data.get("passwd2"):
# You cannot raise a ValidationError because you are not in the clean() method, so you need to add the error through the add_error method.
self.add_error("passwd2", ValidationError('passwords are not the same', 'passwd_mismatch')
# You could also use None instead of "passwd2" if you do not want the error message to be linked to the field.
if not self.errors:
return True
return False
This way, you get the pre-set error messages, django handles the fields requirements when you call the super().is_valid().
Upvotes: 0
Reputation: 53316
To validate such cases, you should use clean()
method of a form, rather than raising an error in the view.
This is nicely explained at Cleaning and validating fields that depend on each other
Upvotes: 2