No Time Dad

A blog about web development written by a busy dad

Quick User Registraion With Django

Kickstart

Assuming you have a virtualenv created with Django installed, you can use the shell script below to get quickly spun up from scratch. You should be able to drop most of the code in this tutorial straight into an existing Django application though if you wanted to.

!#/usr/bin/bash

# rm -rf venv
# python3 -m venv venv
# source venv/bin/activate
# pip install django

django-admin startproject auth_project
cd auth_project
django-admin startapp auth_demo
python manage.py makemigration
python manage.py migrate
python manage.py runserver

Intro

Django is my goto framework when building applications. It handles most of the nitty-gritty things out of the box and the documentation is superb. I know a lot of people complain about “django bloat” but I really dislike writing authentication and repetitve views/endpoints by hand. If you’re looking to iterate quickly and get a product out then I cannot recommend Django or any other “batteries included” framework (Rails, Laravel, etc) enough. In my opinion, rolling all of this stuff by hand is a total waste of time when you need to get a product out in a short amount of time. Frameworks like Django just work and are battle tested. Let’s get started.

Creating the Views

Django provides some reusable views and forms for handling user related things like login, logout, password change, password reset, etc. You can read more about the Authentication Views here. Django does not provide a view for registering users, but it does provide a UserCreationForm and a generic FormView which we can use to build our user registration form.

Starting with views.py, below is what the registration view will look like. We are also going to include a profile view because we want to log the user in after they register.

# views.py
from django.contrib.auth import login
from django.contrib.auth.forms import UserCreationForm
from django.views.generic.edit import FormView
from django.contrib.auth.models import User
from django.contrib.auth import login
from django.views.generic.base import TemplateView
from django.urls import reverse_lazy


class RegisterView(FormView):
  model = User
  form_class = UserCreationForm
  success_url = reverse_lazy('profile')
  template_name = 'registration/create_user.html'

  def form_valid(self, form):
    user = form.save()
    login(self.request, user)
    return super().form_valid(form)


class ProfileView(TemplateView):
    template_name = "user/profile.html"

In the RegisterView class the important things to note are that we are using the User model and the UserCreationForm, both supplied by Django. We also define a few properties that say where our create_user.html template lives and where we want to redirect to after a user has been successfully created. We then override the form_valid method in FormView and add logic to save the form data and log the user in. You’ll notice that we did not have to create any models and we did not have to explicitly write any GET or POST handlers for this.

The ProfileView class simply renders a basic profile for the user upon successful registration.

Creating the Templates

Now we need to create the templates that are referenced in views.py above. In our application directory, we’ll create a directory called “templates” (if it does not already exist) and another directory called “registration” inside the templates directory. We can then create create_user.html in the registration directory. We’ll create the quickest and most simple version of the registration form.

# templates/registration/create_user.html

{% block content %}
<h2>Register</h2>

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

{% endblock %}

And we’ll add a simple profile template in templates/user/ called profile.html.

{% if user.is_authenticated %}
  <p>Welcome, {{ user.username }}. Thanks for logging in.</p>
{% else %}
  <p>Welcome, new user. Please log in.</p>
{% endif %}

Updating the Urls

The last thing we need to do is update urls.py. In this example I am going to map the views to accounts/register/ and accounts/profile/ but you can obviously point the views to whatever url you’d like.

# urls.py
...
from auth_demo.views import RegisterView, ProfileView
...

urlpatterns = [
    ...
    path('accounts/register/', RegisterView.as_view(), name="register"),
    path('accounts/profile/', ProfileView.as_view(), name="profile"),
    ...
]

Conclusion

So now we can start the server if it isn’t running already with python manage.py runserver and navigate to http://127.0.0.1:8000/accounts/register/ and see our new registration view. The form will look something like this:

ReigstrationForm

You’ll likely want to add your own styling and maybe override some default settings in the FormView like help_text, but this was really very painless and a pretty minimal amount of code considering what you get.