1

I'm using Django 1.9.8 and I'm trying to learn how to use form validation. I'm working on a form for registering users. I have 2 problems that I'm stuck on.

  1. The field for re-entering the password isn't accessible (rather, just not there at all) in the forms.py file methods. When I use raise Exception(self.cleaned_data.get('password')) to view the content, the password is shown. I can also view the username and email. When I do the same for the repassword field, it shows None Edit - this was solved by changing the forms.py file to use a clean() method

  2. The validation errors are not displaying at all on my form. If there are errors the redirect back to the form is working, but there is nothing in the inputs for the user to fix, nor is the error displayed. Edit - solved by changing the RegisterForm call after the else statement to form = RegisterForm(request.POST)

Here is the forms.py file

#forms.py
class RegisterForm(forms.Form):
    username = forms.CharField(label="Username", max_length=30,
                               widget=forms.TextInput(attrs={'class': 'form-control', 'name': 'username'}))
    email = forms.CharField(label="Email", max_length=30,
                               widget=forms.TextInput(attrs={'class': 'form-control', 'name': 'email'}))
    password = forms.CharField(label="Password", max_length=30,
                               widget=forms.TextInput(attrs={'class': 'form-control', 'name': 'password', 'type' : 'password'}))
    repassword = forms.CharField(label="RePassword", max_length=30,
                               widget=forms.TextInput(attrs={'class': 'form-control', 'name': 'repassword', 'type' : 'password'}))

    #Edit - this was changed to the clean() function in the selected answer.
    def clean_password(self):
        password1 = self.cleaned_data.get('password')
        password2 = self.cleaned_data.get('repassword')
        #raise Exception(self.cleaned_data.get('repassword')) # None is displayed

        if password1 and password1 != password2:
            raise forms.ValidationError("Passwords don't match")
        return self.cleaned_data

Here's the form template

#register.html

{% if form.errors %}
    <h2>ERROR!</h2>
    {% for field in form %}
        {% for error in field.errors %}
            <div class="alert alert-error">
                <strong>{{ error|escape }}</strong>
            </div>
        {% endfor %}
    {% endfor %}
{% endif %}

<form method="post" action="" id="RegisterForm">
{% csrf_token %}
    <p class="bs-component">
        <table>
            <tr>
                <td>{{ form.username.label_tag }}</td>
                <td>{{ form.username }}</td>
            </tr>
            <tr>
                <td>{{ form.email.label_tag }}</td>
                <td>{{ form.email }}</td>
            </tr>
            <tr>
                <td>{{ form.password.label_tag }}</td>
                <td>{{ form.password }}</td>
            </tr>
             <tr>
                <td>{{ form.repassword.label_tag }}</td>
                <td>{{ form.repassword }}</td>
            </tr>
        </table>
    </p>
    <p class="bs-component">
        <center>
            <input class="btn btn-success btn-sm" type="submit" value="Register" />
        </center>
    </p>
    <input type="hidden" name="next" value="{{ next }}" />
</form>

Here's the view

#views.py
class RegisterViewSet(viewsets.ViewSet):

    #GET requests
    def register(self,request):
        return render(request, 'authorization/register.html', {'form': RegisterForm})

    #POST requests
    def create(self,request):
        form = RegisterForm(request.POST)
        if form.is_valid():
            username = request.POST['username']
            email = request.POST['email']
            password = request.POST['password']
            user = User.objects.create_user(username,email,password)
            user.save()
            return HttpResponseRedirect('/users')
        else:
            return render(request, 'authorization/register.html', {'form': RegisterForm })
            #changed the previous line to the following. This fixed the errors not displaying
            #return render(request, 'authorization/register.html', {'form': RegisterForm(request.POST) }) 

1 Answer 1

2

I am not %100 sure why self.cleaned_data.get('repassword') returns None in that method, however clean_password is not the right place for performing validations of fields that depend on each other.

According to docs, you should perform that kind of validation in clean() function:

views.py

def register(self,request):
    form = RegisterForm() # Notice `()` at the end
    return render(request, 'authorization/register.html', {'form': form})

forms.py

...

def clean(self):
    cleaned_data = super(RegisterForm, self).clean()

    password1 = cleaned_data.get('password')
    password2 = cleaned_data.get('repassword')

    if password1 and password1 != password2:
        raise forms.ValidationError("Passwords don't match")

Please note that you don't have to implement clean_password and clean_repassword.

(If you think you still have to implement clean_password, you have to return password1 from it, not self.cleaned_data.)

You also need to render form errors correctly as described in the docs.

Don't forget to add it in your template:

{{ form.non_field_errors }}

As for the second error, the problem is, every time the validation fails you are returning a new fresh RegisterForm instance instead of the invalidated one.

You should change the line in create() function:

return render(request, 'authorization/register.html', {'form': RegisterForm}) 

to this:

return render(request, 'authorization/register.html', {'form': form})
Sign up to request clarification or add additional context in comments.

8 Comments

The repassword field is now accessible in the forms.py file and validating correctly, but the form is still blank upon redirect, and no errors are being displayed. Any other suggestions?
Did you change the related line to return render(request, 'authorization/register.html', {'form': form}) in the else clause? Also you should update your template like how it is explained in the docs here.
Yes, I even copied and pasted it to be 100% sure there were no spelling errors.
I did that too. I'll update template above to reflect. Regardless, shouldn't the form inputs have the content filled in? They're empty for me.
Yes it should have. You are probably doing something that is not shown in your question. You should put a breakpoint to make sure you hit the else clause when form.is_valid() returns false.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.