Skip to main content

Welcome to a Grasp lesson

Create a free account to keep studying and create your own study path.

Lesson 32

User Authentication: Registration, Login, and Logout

Recommended resources

Hello! In our last lesson, you successfully integrated Django's authentication system, activated the built-in URLs, and created a working login page. This was a crucial first step toward making your task manager a real multi-user application.

Currently, only a pre-existing user (like the one you created in the admin panel) can log in, and there's no way to log out from the main site. This lesson will complete the core authentication workflow. Our goal is to implement user registration, login, and logout functionality that is fully accessible from the user interface.

We will cover:

  • Creating a user registration (signup) page using Django's UserCreationForm.
  • Implementing a secure logout process.
  • Displaying success and error messages to the user.
  • Making your site's navigation dynamic to show the correct links based on whether a user is logged in or out.

By the end of this lesson, you'll have a complete and standard user authentication loop ready for your portfolio project.

1. User Registration (Signup)

While Django's built-in auth.urls provides a login view, it doesn't include one for registration. We need to build this ourselves. Fortunately, Django gives us a powerful tool to make this easy: UserCreationForm. This special form handles all the necessary logic for creating a user, including:

  • Validating that the username isn't already taken.
  • Ensuring the two password fields match.
  • Securely hashing the password so it's not stored in plain text.

We will use a Class-Based View (CreateView) to handle the registration process, which is consistent with the views we built in previous modules.

To see how this comes together, we'll follow the clear guide from the LearnDjango tutorial.

Django Login, Logout, Signup, Password Change, and ...

This section from the 'Django Login, Logout, Signup...' tutorial provides a complete, self-contained guide for building the signup functionality using a Class-Based View.

Read the 'Sign Up Page' section. Follow the steps to: Create a new accounts app (a good practice for custom user logic). Don't forget to add it to INSTALLED_APPS. Create accounts/urls.py and include it above the default auth URLs in your project's urls.py. Implement the SignUpView in accounts/views.py using CreateView and UserCreationForm. Create the registration/signup.html template.

After following those steps, you will have a functional signup page at /accounts/signup/. When a user successfully registers, they will be redirected to the login page as defined by success_url = reverse_lazy("login").

A common and user-friendly practice is to automatically log the user in right after they register. The realpython.com article explains how to do this with just two extra lines of code in your view.

Get Started With Django User Management

The 'Get Started With Django User Management' article shows how to automatically log in a user after registration. We can adapt this for our SignUpView.

In the 'Implement User Registration' section, find the sign_up view. Notice the lines user = form.save() and login(request, user). The login function is the key. You'll need to adapt this for your class-based SignUpView.

To implement this in your SignUpView, you'll need to override the form_valid method. This method is called after the form is successfully validated, making it the perfect place to save the user and then log them in.

Here's how you can modify your SignUpView:

# accounts/views.py
from django.contrib.auth import login # Import the login function
from django.contrib.auth.forms import UserCreationForm
from django.urls import reverse_lazy
from django.views.generic import CreateView

class SignUpView(CreateView):
    form_class = UserCreationForm
    # Instead of reverse_lazy, let's redirect to the main task list ('tasks')
    # on successful registration and login.
    success_url = reverse_lazy("tasks") 
    template_name = "registration/signup.html"

    # We override form_valid to log the user in
    def form_valid(self, form):
        # This calls the default behavior, which saves the user
        response = super().form_valid(form) 
        # self.object is the user object that was created
        login(self.request, self.object) 
        return response

With this change, new users will be seamlessly logged in and taken directly to the main application page.


2. Login, Logout, and User Feedback

Now that users can register, let's complete the cycle with login and logout, and add helpful messages to guide them.

Dennis Ivy's crash course video provides an excellent visual walkthrough of the entire process, from processing the registration form to implementing login, logout, and user feedback messages.

User Registration and Login Authentication | Django (3.0) Crash Course Tutorials (pt 14)

This video covers the full registration-login-logout loop using function-based views. While we are using a class-based view for signup, the concepts for processing forms, handling login/logout, and using the messages framework are identical and very clearly explained.

Watch the following segments: Registration Form Processing (01:29 - 02:45): This reinforces how the UserCreationForm is processed in a view when a POST request is made. User Feedback with Messages (15:58 - 22:09): Pay close attention to how Django's messages framework is used to show a success message after registration and how to display these messages in a template. This is a key technique for good UX. Login Authentication (22:09 - 26:12): This explains the core logic of authenticating a user with a username and password. Although you are using the built-in LoginView, this shows you what's happening under the hood. Logout and Error Handling (26:12 - 32:07): This demonstrates how to build a logout view and, importantly, how to create a form for the POST request required for logging out.

Let's break down the key actions.

Implementing Logout

As mentioned in the video and other resources, logging out requires a POST request for security reasons. This means you can't just use a simple <a> tag link. You need to use a small form.

First, let's configure the redirect. Just like with LOGIN_REDIRECT_URL, we can tell Django where to send the user after they log out. Add this to your settings.py:

# your_project/settings.py

# ... other settings

LOGOUT_REDIRECT_URL = '/' # Redirect to the homepage after logout

Now, you can add the logout form to your base template or navigation bar.

Dynamic Navigation with user.is_authenticated

Your application should be smart enough to show "Login" and "Sign Up" links to guests, and a "Logout" link to authenticated users. The user object is available in every Django template, and its is_authenticated attribute is a boolean that tells you the user's status.

Here's how you can update a navigation section in your base.html template to be dynamic:

<!-- In your base.html or a navigation partial -->
<nav>
    <a href="{% url 'tasks' %}">Home</a>
    {% if user.is_authenticated %}
        <span>Hello, {{ user.username }}!</span>
        <!-- Logout Form -->
        <form action="{% url 'logout' %}" method="post" style="display: inline;">
            {% csrf_token %}
            <button type="submit">Logout</button>
        </form>
    {% else %}
        <a href="{% url 'login' %}">Login</a>
        <a href="{% url 'signup' %}">Sign Up</a>
    {% endif %}
</nav>

This snippet does three things:

  1. Checks if the user is logged in.
  2. If they are, it greets them by name and displays the logout form.
  3. If they are not, it displays links to the login and signup pages.

Displaying Flash Messages

As shown in the video, the messages framework is perfect for one-time notifications. To use it, you first need to add a place in your base.html to render any incoming messages. It's common to place this just inside the <body> tag.

<!-- base.html -->
<body>
    {% if messages %}
        <ul class="messages">
            {% for message in messages %}
                <li{% if message.tags %} class="{{ message.tags }}"{% endif %}>{{ message }}</li>
            {% endfor %}
        </ul>
    {% endif %}
    
    {% block content %}{% endblock %}
</body>

Now, whenever you call messages.success(request, "Your message") in a view, it will appear here after the redirect. For example, if you wanted to add a success message after login (instead of auto-logging in after signup), you could create a custom login view and add it there. The built-in LoginView doesn't add messages by default, but errors will be displayed within the form itself if you include {{ form.non_field_errors }} or loop through form.errors in your login.html.

Test your understanding!

A user tries to register with a username that already exists in the database. What happens, and which component is responsible for this?

Show answer

The UserCreationForm will fail its validation (form.is_valid() will return False). It will then be re-rendered on the signup page, now containing an error message indicating that the username is already taken.

The component responsible is the UserCreationForm itself. It has built-in validation logic to check for unique usernames against the User model.


Conclusion

Excellent! You have now implemented a complete, standard, and secure user authentication workflow. Users can now sign up for an account, log in, and log out.

Key Takeaways:

  • Registration: Use Django's UserCreationForm combined with a CreateView to easily and securely handle new user signups. You can automatically log a user in by overriding the form_valid method.
  • Logout: Logging out requires a POST request to the logout URL. This is typically done with a small form containing a submit button.
  • Dynamic UI: The {{ user.is_authenticated }} template variable is the key to creating a dynamic user interface that adapts based on the user's authentication status.
  • User Feedback: The Django messages framework is the standard way to provide one-time notifications to users, such as "Account created successfully."

Preview of the Next Lesson:
Our application can now distinguish between logged-in users and guests. However, the task list is still visible to everyone. In the next lesson, "Protect views from unauthorized access using LoginRequiredMixin and the @login_required decorator," we will lock down our application so that only authenticated users can view and manage tasks.