Django Creating Users using UserCreationForm

Django authentication framework provides a form named UserCreationForm (which inherits from ModelForm class) to handle the creation of new users. It has three fields namely username, password1 and password2 (for password confirmation). To use UserCreationForm ModelForm you have to first import it from django.contrib.auth.forms as follows:

from django.contrib.auth.forms import UserCreationForm

Unfortunately, Django doesn't provide any view to handle the creation of users, so we have to create our own view.

Add the following url pattern to the beginning of the urlpatterns list.

urlpatterns = [
    url(r'^register/$', views.register, name='register'),
    ...
]    

Create a view function called register() in views.py as follows:

from django.contrib.auth.forms import UserCreationForm
...

def register(request):
    if request.method == 'POST':
        f = UserCreationForm(request.POST)
        if f.is_valid():
            f.save()
            messages.success(request, 'Account created successfully')
            return redirect('register')

    else:
        f = UserCreationForm()

    return render(request, 'blog/register.html', {'form': f})

Next, create a new template register.html in cadmin app with the following code:

{% extends "cadmin/base.html" %}

{% block title %}
    Create User - {{ block.super }}
{% endblock %}

{% block content %}

     <div class="login">

         {% if messages %}
            <ul>
                {% for message in messages %}
                <li>{{ message }}</li>
                {% endfor %}
            </ul>
        {% endif %}

        <h1>Create account - The Great Django Blog</h1>

         <form method="post" >
             {% csrf_token %}
             <table>
                {{ form.as_table }}
                 <tr>
                    <td></td>
                    <td><input type="submit" name="submit" value="Register" /></td>
                </tr>
             </table>
         </form>
     </div>

{% endblock %}    

To view registration form visit http://127.0.0.1:8000/cadmin/register/ and you will get a page like this.

[img]

Create a new user by entering username and password. On success you will be greeted with "Account created successfully" message.

[img]

If entered username already exists or passwords don't match then the form will display errors like this:

[img]

It is important to note that user created using UserCreationForm will have is_superuser and is_staff set to False but is_active set to True.

The only drawback of UserCreationForm is that it doesn't have email field. As a result, it can't send email verification to the user to verify the account.

Most of the time a user registration involves the following steps:

  1. User fills the registration form and hit submit.
  2. Send an email verification to the submitted email.
  3. The user click on the activation link to verify the account.

At this point we have two options:

  1. Extend the UserCreationForm to include email field and email verification capability.
  2. Create a completely new user registeration form from scratch.

We will go with the second option because it allows us to control every aspect of user creation process. Further, it will also reinforce your understanding of working with the forms.

Lets create a new class called CustomUserCreationForm in forms.py file and add the following code. If forms.py doesn't already exists create the file now.

from django.contrib.auth.forms import UserCreationForm
from django.contrib.auth.models import User
from django import forms
from django.core.exceptions import ValidationError

class CustomUserCreationForm(forms.Form):
    username = forms.CharField(label='Enter Username', min_length=4, max_length=150)
    email = forms.EmailField(label='Enter email')
    password1 = forms.CharField(label='Enter password', widget=forms.PasswordInput)
    password2 = forms.CharField(label='Confirm password', widget=forms.PasswordInput)

    def clean_username(self):
        username = self.cleaned_data['username'].lower()
        r = User.objects.filter(username=username)
        if r.count():
            raise  ValidationError("Username already exists")
        return username

    def clean_email(self):
        email = self.cleaned_data['email'].lower()
        r = User.objects.filter(email=email)
        if r.count():
            raise  ValidationError("Email already exists")
        return email

    def clean_password2(self):
        password1 = self.cleaned_data.get('password1')
        password2 = self.cleaned_data.get('password2')

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

        return password2

    def save(self, commit=True):
        user = User.objects.create_user(
            self.cleaned_data['username'],
            self.cleaned_data['email'],
            self.cleaned_data['password1']
        )
        return user

Here we are defining four fields namely username, email, password1 and password2; with their own clean_<field_name>() method (except for password1 field). Notice widget=forms.PasswordInput in both the password fields. forms.PasswordInput forces the CharField to be rendered as password field (<input type="password" ..>) rather than text field (<input type="text" ... >).

The clean_username() and clean_email() method checks for duplicate username and email respectively. The clean_password2() method checks whether the pasword entered in both the fields matches or not. Finally, the save() method saves the data into the database.

Open cadmin's views.py file and update register() view to use CustomUserCreationForm.

from .forms import CustomUserCreationForm
...

def register(request):
    if request.method == 'POST':
        f = CustomUserCreationForm(request.POST)
        if f.is_valid():
            f.save()
            messages.success(request, 'Account created successfully')
            return redirect('register')

    else:
        f = CustomUserCreationForm()

    return render(request, 'cadmin/register.html', {'form': f})

Our registration form is almost ready for now. Visit http://127.0.0.1:8000/cadmin/register/ to create some new users.

If account creation succeeds then you will get a "Account created successfully" message as follows:

[img]

On the other hand, if CustomUserCreationForm encounters any errors. They will be displayed in the form as follows:

[img]

Notice that CustomUserCreationForm uses forms.Form rather than forms.ModelForm. We have deliberately done this to show you everything we have learned about the forms is still usable. If we wanted we could use easily use form.ModelForm instead of forms.Form. This is not the final version of registration form, we will keep updating this form in the upcoming chapters.

Another thing you might have noticed is that we haven't implemented email verification in our CustomUserCreationForm, the reason is that email verification requires us store some additional data about user. At this point we have no way of storing additional data about User. To store additional data we have to extend our User model class. We will see how it's done in the next chapter.