Get AI summaries of any video or article — Sign up free
Python Django Tutorial: Full-Featured Web App Part 6 - User Registration thumbnail

Python Django Tutorial: Full-Featured Web App Part 6 - User Registration

Corey Schafer·
5 min read

Based on Corey Schafer's video on YouTube. If you like this content, support the original creators by watching, liking and subscribing to their content.

TL;DR

Create a dedicated users app to keep registration forms, templates, and routes separate from blog functionality.

Briefing

A complete Django user registration flow is built end-to-end: a dedicated “users” app, a register route and view, a template with CSRF protection, server-side validation using Django’s built-in UserCreationForm, and user feedback via one-time flash messages. The key outcome is that submitting the registration form now actually creates real user accounts in the database—while also showing clear validation errors when input is wrong—so the app can move beyond a static form and toward a production-ready onboarding step.

The work starts by separating concerns. Instead of mixing account logic into the blog code, a new Django app named “users” is created and added to INSTALLED_APPS. That structure keeps user forms, templates, and routes isolated from the blog itself, making future changes easier to locate and maintain.

Next comes the register view. A register function is added to users/views.py and wired to a /register URL in the project’s urls.py. The view initially renders an empty registration form on GET requests. On POST requests, it binds submitted data to the form instance, checks form validity with form.is_valid(), and then pulls the cleaned username from form.cleaned_data. When validation succeeds, a success flash message is queued (using Django’s messages framework) and the user is redirected to the blog home page. When validation fails—such as when a username already exists or the two password fields don’t match—the same bound form is re-rendered, preserving the user’s input and displaying field-level errors.

Once validation works, the flow is upgraded to persist accounts. Inside the success branch, form.save() is called, which creates the new user and automatically handles password hashing. The tutorial then extends the registration form to include an email field, since the default UserCreationForm only covers username and passwords. This is done by creating a custom form class (user register form) in users/forms.py that inherits from Django’s UserCreationForm, adds an email field, and uses a Meta configuration to define the model and field order.

Finally, the registration page is made usable and visually consistent. The template is improved by integrating django-crispy-forms. After installing Django-crispy-forms, adding crispy_forms to INSTALLED_APPS, and setting crispy_template_pack to Bootstrap 4, the template loads crispy_forms_tags and renders the form using the |crispy filter. This produces Bootstrap-styled form layout, required-field indicators, and clearer red error highlighting under invalid inputs.

By the end, the /register page supports real account creation, includes email capture, protects submissions with CSRF tokens, provides one-time success alerts via flash messages, and delivers polished validation feedback—laying the groundwork for the next step: front-end login/logout and access control for authenticated users.

Cornell Notes

The registration system is implemented as a dedicated Django “users” app with a /register route, a register view, and a template that renders a form securely and consistently. The view uses Django’s built-in UserCreationForm for server-side validation: GET requests show an empty form, while POST requests bind submitted data, check form.is_valid(), and either flash a success message + redirect or re-render the form with errors. After validation succeeds, form.save() creates the user and hashes the password automatically. The default form is extended with an email field via a custom form class in users/forms.py, and django-crispy-forms is added to style the page with Bootstrap 4 and improve validation display.

Why create a separate “users” app instead of putting registration logic into the existing blog app?

Account-related functionality (forms, templates, and routes) is logically separate from blog posting. Creating a dedicated users app keeps those files contained, so future changes to registration or authentication are easier to find and less likely to tangle with blog code. The tutorial creates the app with python manage.py startapp users and then adds users.apps.users config to INSTALLED_APPS.

How does the register view handle GET vs POST requests, and why does that matter?

On GET, the view instantiates an empty registration form and renders it. On POST, it instantiates the form with request.POST data, then checks form.is_valid(). If valid, it uses cleaned_data to extract the username, flashes a success message, and redirects to the blog home page. If invalid, it falls through to rendering the template with the bound form so Django can display field errors while preserving the submitted values.

What role do Django’s built-in UserCreationForm and form.is_valid() play?

UserCreationForm provides the username, password, and password confirmation fields plus built-in validation rules (like password length and matching confirmation). form.is_valid() triggers those checks. When the form is invalid (e.g., username already exists or passwords don’t match), the template re-renders with error messages tied to the specific fields.

How does the tutorial ensure the registration actually creates users in the database?

After form.is_valid() succeeds, the view calls form.save(). That single call creates the user record and automatically hashes the password, so no manual hashing logic is needed. Without form.save(), submissions would validate but redirect without persisting a new user.

How is the email field added to registration when UserCreationForm doesn’t include it?

A custom form class is created in users/forms.py that inherits from UserCreationForm. It adds email = forms.EmailField() and defines an inner class Meta with model = user and fields = ['username', 'email', 'password1', 'password2'] (in the tutorial’s order). The view then uses this custom form instead of the default UserCreationForm, so the saved user includes an email address.

Why integrate django-crispy-forms, and what changes in the template?

crispy forms improves layout and validation feedback without manually adding Bootstrap classes to every field. After installing Django-crispy-forms, adding crispy_forms to INSTALLED_APPS, and setting crispy_template_pack = 'bootstrap4', the template loads crispy_forms_tags and renders the form with {{ form|crispy }}. This automatically generates Bootstrap-styled markup and highlights invalid fields with clear red error messages.

Review Questions

  1. What specific code-path differences occur in the register view between request.method == 'POST' and other methods, and how does each path affect what the user sees?
  2. Where does the email field come from in the final registration form, and how does the custom form’s Meta configuration control which fields appear and in what order?
  3. How do flash messages and redirects work together after successful registration, and where must the template be updated to display those messages?

Key Points

  1. 1

    Create a dedicated users app to keep registration forms, templates, and routes separate from blog functionality.

  2. 2

    Add the users app to INSTALLED_APPS so Django can discover its configuration and templates.

  3. 3

    Use Django’s UserCreationForm for registration validation, binding request.POST data on POST requests and rendering an empty form on GET.

  4. 4

    Call form.save() only after form.is_valid() to persist the user and automatically hash the password.

  5. 5

    Extend registration with an email field by inheriting from UserCreationForm in users/forms.py and defining Meta.model and Meta.fields.

  6. 6

    Protect the registration form with a CSRF token in the template so POST submissions are accepted securely.

  7. 7

    Render the form with django-crispy-forms (|crispy) and Bootstrap 4 to get consistent styling and clearer red validation errors.

Highlights

The register view is split cleanly by HTTP method: GET shows an empty form, POST binds submitted data, validates, and either redirects with a flash message or re-renders with field errors.
Calling form.save() after successful validation is what turns a working form into real account creation, including automatic password hashing.
Adding email requires a custom form class that inherits from UserCreationForm and defines Meta.fields to include email.
django-crispy-forms turns the registration template from manually styled fields into a Bootstrap 4-ready form with improved error highlighting.
Flash messages are displayed site-wide by placing the messages loop in the base template above the content block.

Topics

  • Django Users App
  • User Registration View
  • Form Validation
  • Email Field Extension
  • django-crispy-forms

Mentioned