• 12 hours
  • Medium

Free online content available in this course.

course.header.alt.is_video

course.header.alt.is_certifying

Got it!

Last updated on 3/2/22

Create a Sign up Page

Create a Sign up Page

Our site now has all of the necessary functionality for authenticating users. Next, we can add a sign up page.

All of the forms used in the class-based authentication views are also available on their own, allowing you to use them when implementing your own log in views. While Django does not provide a class-based view for sign up, it does provide a  UserCreationForm  . 

You can import all of the forms in the  auth  package from  django.contrib.auth.forms  . 

Let's use the  UserCreationForm  to implement a sign up view. 

Implement sign-up view with UserCreationForm
Implement sign up view with  UserCreationForm

Step 1: Subclass the UserCreationForm

The  UserCreationForm  is a  ModelForm  that has three fields:  

  • username  

  • password1  

  • password2 

As we also require some other fields from the user, we will have to subclass this form to use it.

First, inherit from the form and add your fields.

# authentication/forms.py
from django.contrib.auth import get_user_model
from django.contrib.auth.forms import UserCreationForm


class SignupForm(UserCreationForm):
    class Meta(UserCreationForm.Meta):
        model = get_user_model()
        fields = ('username', 'email', 'first_name', 'last_name', 'role')

Because we are subclassing a  ModelForm , it is best practice to also inherit from the inner class  Meta  when extending the form. 

We are also using the utility method  get_user_model  , which allows you to get the  User  model without importing it directly. This is particularly important if you are building an app designed for reuse in different projects. 

Step 2: Add a Sign up View

Now that we have the form, it is a simple task of adding a view, writing the template, and including it in the URL patterns.

First the view:

# authentication/views.py
from django.conf import settings
from django.contrib.auth import login
from django.shortcuts import redirect, render

from . import forms


def signup_page(request):
    form = forms.SignupForm()
    if request.method == 'POST':
        form = forms.SignupForm(request.POST)
        if form.is_valid():
            user = form.save()
            # auto-login user
            login(request, user)
            return redirect(settings.LOGIN_REDIRECT_URL)
    return render(request, 'authentication/signup.html', context={'form': form})

The best way to access the configured settings is to import  django.conf.settings . This allows you to access  LOGIN_REDIRECT_URL , which you'll use for the redirect on successful sign up. You also used the  login  function to log the user in automatically.

Step 3: Configure the Templates

Next, the template:

# authentication/templates/authentication/signup.html
{% extends 'base.html' %}
{% block content %}
    <h2>Sign Up</h2>
    {% if form.errors %}
        {{ form.errors }}
    {% endif %}
    <form method="post">
        {{ form.as_p }}
        {% csrf_token %}
        <button type="submit" >Submit</button>
    </form>
{% endblock content %}

Let's also add a sign up link to the log in page.

# authentication/templates/authentication/login.html
{% extends 'base.html' %}
{% block content %}
    <form method="post">
        {{ form.as_p }}
        {% csrf_token %}
        <button type="submit" >Submit</button>
    </form>
    <p>Not a member? <a href="{% url 'signup' %}">Sign up now!</a></p>
{% endblock content %}

Step 4: Add the URL Pattern

Now update the URL patterns.

# fotoblog/urls.py
urlpatterns = [
    ...
    path('signup/', authentication.views.signup_page, name='signup'),
]

Let's see if it worked.

Sign up page
Sign up page

Excellent! Try signing up a user yourself.

You will see all of the restrictions on a password. These are the default password validators for Django, but you can configure these to be as strong or as weak as you want. Let's see how to do that.

Enforce Custom Password Validation

You need to use validators to customize password validation.  Validators are classes used to validate the input of a field. The  auth  module provides four different password validators found in  django.contrib.auth.password_validation  .  

The default validators are:

  • UserAttributeSimilarityValidator  - invalidates the password if too similar to the user's details.

  • MinimumLengthValidator  - invalidates the password below a minimum length.

  • CommonPasswordValidator  - invalidates the password if found in a list of common passwords.

  • NumericPasswordValidator  - invalidates the password if it is all numeric. 

These are all enabled by default but you can configure them by setting  AUTH_PASSWORD_VALIDATORS  in the settings. 

This is the default configuration.

AUTH_PASSWORD_VALIDATORS = [
    {
        'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
    {
        'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
    },
]

Let's say the default password restrictions are too strict, and you want to enforce that the password must:

  • Be at least eight characters long.

  • Contain letters.

  • Contain numbers.

To do this, you would have to create custom validators. Let's see how.

Create custom validators
Create custom validators

Step 1: Create the Validators

First, create a new file called  validators.py  to house your validators.

A validator is a class and only requires two methods; a  validate  method and a  get_help_text  method.

Let's build a validator to check if the password contains a letter.

# authentication/validators.py
from django.core.exceptions import ValidationError


class ContainsLetterValidator:
    def validate(self, password, user=None):
        if not any(char.isalpha() for char in password):
            raise ValidationError(
                'The password must contain a letter', code='password_no_letters')
    
    def get_help_text(self):
        return 'Your password must contain at least one upper or lower case letter.'

 The  validate  method checks the password and raises a  ValidationError  if the password fails the criteria. The  get_help_text  method provides the end user with guidance on how to pass the validation. 

Step 2: Configure the Settings to Use the Custom Validator

Now that the validator is built, let’s add it to the settings. We will also use the  MinimumLengthValidator  , which we can configure using the  OPTIONS  key. 

# fotoblog/settings.py
AUTH_PASSWORD_VALIDATORS = [
   {
       'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
       'OPTIONS': {
           'min_length': 8,
       }
   },
   {
       'NAME': 'authentication.validators.ContainsLetterValidator',
   },
]

Check out the sign up page now.

Screenshot of a sign up page with updated help text
Screenshot of a sign up page with updated help text

It looks like it worked! Try testing out the password functionality.

These validators are great for passwords, but you can also use them for other fields.

If you wanted to check if a postcode is valid, you could define a  PostCodeValidator  in your validators file and then specify it in the form. 

from . import validators


class PostCodeForm(forms.Form):
    post_code = forms.CharField(max_length=10, validators=[validators.PostCodeValidator])

You can now validate inputs and make sure that the data in your database is consistent.

Exercise: Create Your Own Password Validator

You know how to check to see if user passwords contain any letters. Now check to see if they have at least one number.

Try creating a validator that will check the password to see if they contain a number using

if not  any(character.is_digit() for character in password)   . 

You will need to:

  • Create the validator  ContainsNumberValidator  in  authentication/validators.py  .

  • Configure  AUTH_PASSWORD_VALIDATORS  in the settings to use the validator. 

Once you finish, check your implementation against the solution in GitHub repo

Find and Use Third-Party Django Packages

We have built an  authentication  app that can handle signing up and logging in users, but we could add a lot more authentication functionality. For example:

  • Email verification.

  • Single sign in integration with social accounts.

  • Password reset emails.  

To build all of these features would be a large undertaking. And yet, these are tasks that are common to many sites.

Do I have to recreate this for every project? 

No, you don't.

A large community of developers supports Django, many of whom create and publish reusable packages that the community can use.

Look for these in Django Packages

Follow along in the screencast to explore Django Packages and see how I would find one to set up authentication more quickly and easily.

There are several considerations when selecting a package.

  • It is actively maintained. An unmaintained project will not receive updates to be compatible with new Django versions, and bugs will not get fixed. You can see when the repository was last updated on GitHub.

  • It is popular. More popular projects are less likely to contain bugs and are also more likely to have a community of developers who will actively open pull requests to fix bugs. A good way to gauge the popularity of a repository is to see the number of stars on GitHub.

  • It is compatible with your Python version. 

  • It is compatible with your Django version.

  • Beta or Production. Generally, you want a Production package. There are some robust Django packages out there that are in Beta phase. If it meets all the other criteria and the package is Beta, it's probably OK.

If you are working with a package and you find a bug, raise an issue on GitHub. If you feel courageous, fork the repository, fix it yourself, and then open up a pull request back into the repository. Congratulations, you are now an open-source contributor!

One last thing to note is that many packages are a labor of love, maintained by people on their own time, for no compensation. Questions and offers to help will often be well received, but demanding ones may not get a warm reception!

Let's Recap!

  • You can use Django generic authentication forms in your project to save time.

  • You can specify password validators in the  AUTH_PASSWORD_VALIDATORS  setting.

  • Use Django Packages to find third-party packages to integrate into your site.  

You have successfully built an authentication app. Now, time for a quiz on what you have learned!

Example of certificate of achievement
Example of certificate of achievement