Why my user registration form is not valid?

Hi there,

I am new to Django and I was creating an e-commerce store using Django. I successfully created User Login Form which works perfectly, but I am stuck at User Registration Form. It is not being valid.

My forms.py:

from django import forms
from django.forms.widgets import PasswordInput

class UserLoginForm(forms.Form):
    username = forms.CharField()
    password = forms.CharField(widget=forms.PasswordInput)


class UserRegistrationForm(forms.Form):
    username = forms.CharField()
    email = forms.EmailField()
    password = forms.CharField(widget=forms.PasswordInput)
    password2 = forms.CharField(label='Confirm password', widget=forms.PasswordInput)

    def clean(self):
        data = self.cleaned_data
        password = self.cleaned_data.get('password')
        password2 = self.cleaned_data.get('password2')

        if password2 != password:
            raise forms.ValidationError("Passwords must match")

        return data

My register.html

<div>
    <form method="POST" action="">
        {% csrf_token %}
        {{ form.as_p }}
        <input type="submit" name="Register">
    </form>
</div>

My login.html

<div>
    <form method="POST" action="">
        {% csrf_token %}
        {{ form.as_p }}
        <input type="submit" name="Login">
    </form>
</div>

My views.py

from django.contrib.auth import authenticate, login
from django.shortcuts import render, redirect
from .forms import UserLoginForm, UserRegistrationForm

# Create your views here.

def userRegistrationPage(request):
    form = UserRegistrationForm()

    context = {
            'form': form
        }

    if request.method == 'POST':
        form = UserRegistrationForm(request.POST or None)

        if form.is_valid():
            username = form.cleaned_data.get("username")
            password = form.cleaned_data.get("password")
            print(username, password)
            
        else:
            print("Form is not valid")

    return render(request, 'index/register.html', context)

def userLoginPage(request):
    form = UserLoginForm()

    context = {
            'form': form
        }

    if request.method == 'POST':
        form = UserLoginForm(request.POST or None)

        if form.is_valid():
            username = form.cleaned_data.get("username")
            password = form.cleaned_data.get("password")
            user = authenticate(request, username=username, password=password)
            print(user)
            if user is not None:
                login(request, user)
                # Redirect to a success page.
                return redirect("/")
            else:
                print("Error")

    return render(request, 'index/login.html', context)

My urls.py

from django.urls import path
from . import views

urlpatterns = [
    path('', views.index, name="index-page"), # Home Page
    path('register', views.userRegistrationPage, name='register'), #User Registeration Page
    path('login', views.userLoginPage, name='login'), #User Login Page
]

Everytime I visit localhost:8000/register, I get the message Form is not valid from the if/else condition on form validation in views.py. I did similar process with UserLoginForm and that is working perfectly. Can somebody help me why the form is not being valid? What wrong I am doing? Much appreciated.

There are a couple different things wrong here, that may be caused by copy/pasting from your original, but needing to be pointed out:

The parameter here is widget, not widgets. (3 occurrences)

Your implementation of clean isn’t correct. You’re not calling super on your method to initially populate the cleaned_data dict. See the example at Form and field validation | Django documentation | Django

You’re missing the close-quote after POST.

The is_valid method is a method and not a value.
See the example at: Working with forms | Django documentation | Django

Hi @KenWhitesell,

Actually I did not have access to my computer when I opened this Ticket. I wrote all of the code by myself from my smartphone, so yeah I guessed that there would be these little mistakes. But putting these mistakes aside (I also corrected these in my ticket, thanks for pointing these out), as these are not in my original code that is in my PC, what could be the issue that the form is not being valid?

No way to tell.

Unless you copy/paste the exact code you’re trying to use, we can’t figure out where the mistake is.

Let me update the ticket with my exact code.

Hey, I updated the ticket with my original code and also included login.html template in which UserLoginForm is working perfectly fine, and that means the UserLoginForm form gets valid and so on etc.

From my earlier response:

Your implementation of clean isn’t correct. You’re not calling super on your method to initially populate the cleaned_data dict. See the example at Form and field validation | Django documentation | Django

Also note the or None clause isn’t doing anything for you in your form constructor. See the examples at Working with forms | Django documentation | Django.

Well, I updated my forms.py, the updated one is below:

from django import forms
from django.forms.widgets import PasswordInput

class UserLoginForm(forms.Form):
    username = forms.CharField()
    password = forms.CharField(widget=forms.PasswordInput)


class UserRegistrationForm(forms.Form):
    username = forms.CharField()
    email = forms.EmailField()
    password = forms.CharField(widget=forms.PasswordInput)
    password2 = forms.CharField(label='Confirm password', widget=forms.PasswordInput)

    def clean(self):
        cleaned_data = super().clean()
        data = self.cleaned_data
        password = cleaned_data.get('password')
        password2 = cleaned_data.get('password2')

        if password2 != password:
            raise forms.ValidationError("Passwords must match")

        return data

But, now I am getting this error (screenshot below):

So the error page identifies 5 different elements to investigate - what of these have you checked and validated?

I guess, I did not save the views.py after a minor changing and that’s why that CSRF error was showing up, I saved all the files with the updated forms.py that I posted above, now the page is working but the form is still not valid.

After filling the form, I get Form is not valid in the Terminal as I have put the if/else conditions to print this if the form is not valid.

@KenWhitesell are you there??

@KenWhitesell I finally figured it out that the clean() method and if form.is_valid() conditions, both are working, it’s just raise forms.ValidationError("Passwords must match") is not working in a way that it does not print error on the Front-End when I submit different passwords. As I was testing the form with different passwords, that’s why my form was not valid because it raised error. When I tested it with same passwords it worked perfectly, but point is how should I raise the error so that it prints the error on the Front-End?

Please post a current, accurate copy of the view. (We only need to see the view, unless you’ve made other changes to the form or template.)

Hey @KenWhitesell, here is my current and accurate copy of views.py, just missing the view of the index page (because I think that does not have to do anything with this issue):

from django.contrib.auth import authenticate, login, get_user_model
from django.shortcuts import render, redirect
from .forms import UserLoginForm, UserRegistrationForm

# Create your views here.

User = get_user_model()

def userRegistrationPage(request):
    form    = UserRegistrationForm()

    context = {
            'form': form
        }

    if request.method == 'POST':
        form = UserRegistrationForm(request.POST)

        if form.is_valid():
            username    = form.cleaned_data.get("username")
            email       = form.cleaned_data.get("password")
            password    = form.cleaned_data.get("password")
            print(username, password)
            new_user    = User.objects.create_user(username, email, password)
            print(new_user)
            
        else:
            print("Form is not valid")

    return render(request, 'index/register.html', context)

def userLoginPage(request):
    form = UserLoginForm()

    context = {
            'form': form
        }

    if request.method == 'POST':
        form = UserLoginForm(request.POST)

        if form.is_valid():
            username    = form.cleaned_data.get("username")
            password    = form.cleaned_data.get("password")
            user        = authenticate(request, username=username, password=password)
            print(user)
            if user is not None:
                login(request, user)
                # Redirect to a success page.
                return redirect("/")
            else:
                print("Error")

    return render(request, 'index/login.html', context)

Also, you might need the current and accurate copy of forms.py, and here it is:

from django import forms
from django.forms.widgets import PasswordInput, EmailInput
from django.core.exceptions import ValidationError
from django.contrib.auth import get_user_model

User = get_user_model()

class UserLoginForm(forms.Form):
    username            = forms.CharField()
    password            = forms.CharField(widget=PasswordInput)


class UserRegistrationForm(forms.Form):
    username            = forms.CharField()
    email               = forms.EmailField(widget=EmailInput)
    password            = forms.CharField(widget=PasswordInput)
    password2           = forms.CharField(label='Confirm password', widget=PasswordInput)

    def clean_username(self):
        username        = self.cleaned_data.get('username')
        qs              = User.objects.filter(username=username)
        
        print("checking if user exists")
        if qs.exists():
            raise forms.ValidationError("Username is taken.")

        print("returning username")
        return username

    def clean_email(self):
        email           = self.cleaned_data.get('email')
        qs              = User.objects.filter(email=email)
        
        print("checking if user exists")
        if qs.exists():
            raise forms.ValidationError("Email is taken.")

        print("returning email")
        return email

    def clean(self):
        cleaned_data    = super(UserRegistrationForm, self).clean()
        print("clean is called")
        password        = cleaned_data.get("password")
        password2       = cleaned_data.get("password2")

        if password != password2:
            print("passwords did not match")
            raise forms.ValidationError("Passwords must match.")
        
        print("returning cleaned_data")
        return cleaned_data

Please note that, as I said, clean() method works perfectly fine. It was just printing Form is not valid in the terminal because of the fact that I have made an else case, in userRegistrationPage(), that if UserRegistrationForm form is not valid, print Form is not valid.

However, the UserRegistrationForm form was not valid because I was putting different passwords in password and password2 fields on the Front-End, hence the clean() method was raising ValidationError as it is defined in ``clean()method. On the other hand, if I put same passwords inpasswordandpassword2fieldson the Front-End, theclean()method does not raise error andUserRegistrationForm` form would be valid.

So, now the issue is, despite all of the functionality working correctly, even though the clean() method raise error on entering different passwords in password and password2 fields on the Front-End, that error is not being printed on the Front-End, and the hence use would not know what is happening if he/she does not get message like “Passwords must be same” etc.

I would like to get you noted that, it is the same case with clean_username() and clean_email() methods in UserRegistrationForm in forms.py, the error does not get printed on the Front-End, if the email already exists or the username is taken

One cause of the behavior you are seeing is that you’re rendering the wrong instance of the form in your view.

The line:
form = UserRegistrationForm()
creates an instance of UserRegistrationForm. In this case, it’s an unbound form - I’ll call it URF#1.

Then you have:

    context = {
            'form': form
        }

You’ve created a dict named context, and within that dict you’ve stored a reference to an instance of DRF#1.

Continuing on, you then have:
form = UserRegistrationForm(request.POST)

This is creating a new instance of the form, bound with the POST data from the browser. I’ll call it DRF#2.

You go on to validate that form, and any errors raised are going to be associated with it.

Finally, you have:
return render(request, 'index/login.html', context)

What form is referenced by the context?

DRF#1 - the unbound form without the errors associated with it.

1 Like

@KenWhitesell thank you so much, I corrected my views.py, and it finally shows the rasied ValidationError on the Front-End. Currently my views.py looks like this:

from django.contrib.auth import authenticate, login, get_user_model
from django.shortcuts import render, redirect
from .forms import UserLoginForm, UserRegistrationForm

# Create your views here.

User = get_user_model()
def userRegistrationPage(request):
    form    = UserRegistrationForm(request.POST)

    context = {
            'form': form
        }

    if request.method == 'POST':
        #form = UserRegistrationForm(request.POST)

        if form.is_valid():
            username    = form.cleaned_data.get("username")
            email       = form.cleaned_data.get("password")
            password    = form.cleaned_data.get("password")
            print(username, password)
            new_user    = User.objects.create_user(username, email, password)
            print(new_user)
            
        else:
            print("Form is not valid")

    return render(request, 'index/register.html', context)

def userLoginPage(request):
    form = UserLoginForm(request.POST)

    context = {
            'form': form
        }

    if request.method == 'POST':
        #form = UserLoginForm(request.POST)

        if form.is_valid():
            username    = form.cleaned_data.get("username")
            password    = form.cleaned_data.get("password")
            user        = authenticate(request, username=username, password=password)
            print(user)
            #print(request.user.is_authenticated())
            if user is not None:
                #print(request.user.is_authenticated())
                login(request, user)
                # Redirect to a success page.
                #context['form'] = UserLoginForm()
                return redirect("/")
            else:
                print("Error")

    return render(request, 'index/login.html', context)

and my forms.py is:

from django import forms
from django.forms.widgets import PasswordInput, EmailInput
from django.core.exceptions import ValidationError
from django.contrib.auth import get_user_model

User = get_user_model()

class UserLoginForm(forms.Form):
    username            = forms.CharField()
    password            = forms.CharField(widget=PasswordInput)


class UserRegistrationForm(forms.Form):
    username            = forms.CharField()
    email               = forms.EmailField(widget=EmailInput)
    password            = forms.CharField(widget=PasswordInput)
    password2           = forms.CharField(label='Confirm password', widget=PasswordInput)

    def clean_username(self):
        username        = self.cleaned_data.get('username')
        qs              = User.objects.filter(username=username)
        
        print("checking if user exists")
        if qs.exists():
            raise forms.ValidationError("Username is taken.")

        print("returning username")
        return username

    def clean_email(self):
        email           = self.cleaned_data.get('email')
        qs              = User.objects.filter(email=email)
        
        print("checking if user exists")
        if qs.exists():
            raise forms.ValidationError("Email already exists.")

        print("returning email")
        return email


    def clean(self):
        cleaned_data    = super(UserRegistrationForm, self).clean()
        print("clean is called")
        password        = cleaned_data.get("password")
        password2       = cleaned_data.get("password2")

        if password != password2:
            print("passwords did not match")
            raise forms.ValidationError("Passwords must match.")
        
        print("returning cleaned_data")
        return cleaned_data

Now the problem is, although it works (shows the error on Front-End) for username (if it is taken) and password & password2 (if the don’t match), but it still do not shows error for the email (if it already exists). Any help regarding it will also be appreciated. Thanks again.

1 Like

See Creating forms from models | Django documentation | Django
and
Model instance reference | Django documentation | Django
for a couple of options.

1 Like

Well, I found an error, in views.py I was getting 'password' in the email, look at below code:

if form.is_valid():
            username    = form.cleaned_data.get("username")
            email       = form.cleaned_data.get("password")
            password    = form.cleaned_data.get("password")

and I corrected it to:

if form.is_valid():
            username    = form.cleaned_data.get("username")
            email       = form.cleaned_data.get("email")
            password    = form.cleaned_data.get("password")

and it is working perfectly.

Thanks for all of your help. I am going to mark this case as solved by selecting your second last reply as solution.