a blog about Django & Web Development

Basic User Registration with Django

This tutorial is going to cover how to create users in Django in the most basic way possible.

This tutorial covers:

  • Adding a URL pattern to urls.py
  • Creating a user registration form in forms.py
  • Creating a view in views.py

The need to handle passwords adds some complexity to creating users, compared to creating items in a To Do list. However, Django has built in features like a UserCreationForm that simplifies the process.

Code Example

As usual, the finished code for this tutorial is available on GitHub.

User Model

In Django, it is possible to implement user registration and login without creating your own user model. This is because the Django framework already has a user model built in.

Therefore, this tutorial is not going to cover how to create such a model.

However, the built-in user model cannot be modified. This presents a problem if you want to identify users with their email instead of their username, or add your own custom fields to the model.

Most Django developers will create their own Custom User Model to provide flexibility. I’m not going to go into detail about why you should create your own user model, but I do highly recommend this article by Vladimir Supalov which thoroughly explains when and why you should create one.

As for instructions on how to create a Custom User Model, this article by William Vincent has the code snippets to get you started quickly.

User Registration Form

You don’t need to create your own form to register users, or handle the form data yourself. Django’s built-in user creation form makes it easy for developers to handle passwords.

This form is defined by a class called UserCreationForm, which is import from django.contrib.auth.forms. I highly recommend viewing the source code for this form as it will help you understand what it can do and how it works.

from django.contrib.auth.forms import UserCreationForm

The form provides the following fields:

  • Username
  • Password
  • Password confirmation

It contains code that will compare the two password fields and returns an error if they don’t match. It also runs validation checks on the supplied password, to prevent users from choosing an insecure password.

If you are using Django’s built-in user model, then you don’t need to modify this form. If you are using a custom model, you may need to subclass this form to alter the fields (e.g. you are using email to identify users, rather than a username).

Customising your form

What do you do if you want to customise your form without losing any of the functionality of Django’s UserCreationForm? You may want to do this to assign CSS classes or use Django Crispy Forms (tutorial by Simple Is Better Than Complex).

You can extend the functionality of the UserCreationForm by sub-classing it.

E.g.

class CustomUserCreationForm(UserCreationForm):
   pass

1. Create an app

We will start by creating an app, a module that will contain the code for registering users.

You can create an app by going into your terminal and typing the following line:

python manage.py startapp users

This will create a module called “users”.

Make sure you register your app. You can do this by going into settings.py and add "users" to the list of INSTALLED_APPS.

2. Create a View

As we don’t need to create our own user creation form, we can proceed to creating a view.

Creating a view to handle new user requests is no different to creating any other object in the database. It is simple because it is the User Creation Form that processes the submitted data and handles the passwords.

What our view needs to do…

If the view is requested with a GET request:

  1. Create an empty form
  2. Send the form to the HTML template

If the view is called with a POST request:

  • Create a form populated with the data provided by the user
  • Check the form is valid
  • If the form is valid, then create the user in the database (using form.save()). Then, redirect the user to the homepage.
  • If the form is not valid, then send the form back to the user with the errors.

Create an empty form

To create an empty form, create a new instance of the UserCreationForm class.

form = UserCreationForm()

Send the form to the template

The render function will return a HTTP Response that renders HTML in the browser. The function accepts 3 arguments:

  • The HTTP request
  • The path to your chosen HTML template
  • The context

“Context” is a dictionary of data that you wish to pass to the template. In this example, we will pass a form object (instance of UserCreationForm). You can pass whatever data you like within the context.

context = {"form": form}
return render(request, "registration/registration_form.html", context)

Pass form data to the UserCreationForm

When the form is submitted to the user, we want to pass the data to the UserCreationForm class, so the class can clean and validate the submission.

form = UserCreationForm(request.POST)

This data can be found inside the request object.

Check the form is valid

Django forms contain a method called .is_valid() which will validate the user input. In this case, it will check the username has not already been taken and the passwords match.

form.is_valid()

Create a user

We can create a user by calling form.save(). The save() method contains code that will create a user using the cleaned form data.

form.save()

3. Create a template

We need to create a HTML file that is going to display our form.

In the users directory, create a folder called templates. Inside templates, create another folder called registration. Inside registration, create a file called registration_form.html.

Inside, registration_form.html, add the following code:

<h1>Register</h1>
<form method="post" novalidate>
    {% csrf_token %}
    {{ form.as_p }}
    <input type="submit" value="Register">
</form>

Inside this form, we render the UserCreationForm we instantiated inside the view in Step 2.

By using {{ form.as_p }}, we don’t have to write the HTML for each field. The fields were already defined inside the UserCreationForm class (source code).

4. Create the URL

We need to create URL patterns so that a user can view the registration form after requesting the URL.

When you start a Django project, there is a urls.py file in the project directory. We will create a separate URLs file for our users app.

# users/urls.py

from django.urls import path

from users import views

urlpatterns = [
    path("register", views.register_user, name="register")
]

We need to update our root urls.py to include the URLs in users/urls.py.

# project_config/urls.py

from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path("admin/", admin.site.urls),
    path("", include("users.urls")),
]

Result

So far, we have mapped a URL pattern to our register_user view. The view creates a new instance of Django’s UserCreationForm. On submitting the form, our view will check the submission is valid. If it is valid, it will create the user and redirect the user to the homepage.

If the user’s submission is not valid, then the view will send the form errors to the template.

Without making modifications to our template, our form does display form errors. You can test this by deliberately mismatching the passwords.

Customising the Form

This tutorial covers the bare minimum required to create a user registration form.

In practice, we may want to:

  • Create a custom user model, so users can log in with email instead
  • Get rid of the help text
  • Add CSS
  • Have more control over the layout of the form

I am going to cover these in future tutorials.

In the meantime, I highly recommend this tutorial by Vitor Freitas about using a package called Django Widget Tweaks to customise the form. It is a package that makes it easy to add CSS classes to your form from inside the template, while still keeping some of the benefits of Django forms.

Conclusion

We have created a user registration system using Django’s built-in User model and User Creation Form.

The User and UserCreationForm classes minimise the amount of code we have to write, but don’t leave us with room for customisation. We can inherit these models into custom classes to provide the additional flexibility if required.

Related Posts