How to append errors to form's "non_field_errors" from view?
Here is my situation. I have a web page for users to create their own accounts. On this page, there's reCaptcha to prevent bots. Onece a user click on "Submit", the reCaptcha validation is performed, prior to constructing the corresponding form, in the corresponding view. Let's say the user's input failed the reCaptcha validation. How should I prompt this error back to the user? Should I add the error to the "non_field_errors" of the form? If so, what's the correct way of doing this?
My current approach is to pass a list of errors, including the reCaptcha error, from the view to the form constructor and have the errors added to the form's non_field_errors in the init(). The way I add errors to the form's non_field_errors (referenced post), however, is insufficient though. When there are multiple errors in the list passed, the latter one always overwrites the one before it. How can I append errors to the form's non_field_errors rather then overwriting the existing one each time?
views.py:
def create_account(request):
""" User sign up form """
if request.method == 'POST':
recaptcha_result = check_recaptcha(request)
if recaptcha_result.is_valid:
...
else:
non_form_errors = ['Incorrect reCaptcha word entered. Please try again.'];
signup_form = SignUpForm(request.POST, non_form_errors=non_form_errors)
else:
signup_form = SignUpForm()
public_key = settings.RECAPTCHA_PUBLIC_KEY
script = displayhtml(public_key=public_key)
return render(request, 'create_account.html',
{'signup_form': signup_form, 'script': script})
forms.py:
class SignUpForm(UserCreationForm):
""" Require email address when a user signs up """
email = forms.EmailField(label='Email address', max_length=75, widget=TextInput(attrs={'size': 30}))
def __init__(self, *args, **kwargs):
non_form_errors = []
if kwargs.has_key('non_form_errors'):
non_form_errors.append(kwargs.pop('non_form_errors'))
super(SignUpForm, self).__init__(*args, **kwargs)
for err in non_form_errors:
se开发者_Python百科lf.errors['__all__'] = self.error_class(err)
Try this in forms.py
:
def __init__(self, *args, **kwargs):
non_form_errors = []
if kwargs.has_key('non_form_errors'):
non_form_errors.append(kwargs.pop('non_form_errors'))
super(SignUpForm, self).__init__(*args, **kwargs)
errors = self.errors.get('__all__', [])
for err in non_form_errors:
errors.append(self.error_class(err))
self.errors['__all__'] = errors
First, I would like to thank @lazerscience for pointing out a better direction for a solution to my problem. I, however, didn't adopt the django-recaptcha app as suggested.
I ended up using a code snippet from Marco Fucci. In a quick summary, this code snippet helps you to create a custom form field (and widget) for ReCaptcha. Once this is in place, all you need to do to have ReCaptcha on your form is as simple as adding one line to the form definition.
精彩评论