Setting up allauth in Django

In this tutorial we will set up authentication in a Django project using the popular package allauth and create a few templates for it.

July 5, 2020, 9:18 a.m.
Themes: Authentication

Visit a previous tutorial if you haven't set up a project yet. The first thing we do is install the package in our virtual environment:

pip3 install django-allauth

Add django-allauth to requirements.txt. We need to change a couple of things in our settings file, in our case settings/base.py. If you have followed an earlier tutorial and installed Wagtail, some of these settings have already been added. First, check that django.template.context_processors.request is in context_processors or add it. Then add the required authentication backends:

AUTHENTICATION_BACKENDS = (
    ...
    # Needed to login by username in Django admin, regardless of `allauth`
    'django.contrib.auth.backends.ModelBackend',

    # `allauth` specific authentication methods, such as login by e-mail
    'allauth.account.auth_backends.AuthenticationBackend',
    ...
)

Check that the following apps are in your INSTALLED_APPS:

'django.contrib.auth',
'django.contrib.messages',
'django.contrib.sites',

and add the following ones:

'allauth',
'allauth.account',
'allauth.socialaccount',

All three are required, even if you don't plan on using a social account to log in. We will add specific settings for individual social accounts later. Add:

SITE_ID = 1

if it's not already there. Now go to your project urls.py file (not the urls.py of your app) and add the following to your urlpatterns variable:

from django.urls import path

urlpatterns = [
    ...
    path('accounts/', include('allauth.urls')),
    ...
]

Migrate the database and run the server:

python3 manage.py makemigrations
python3 manage.py migrate
python3 manage.py runserver

Since allauth has a lot of pre-installed templates, views and forms, some of the basic functionality is already available now. For example http://127.0.0.1:8000/accounts/login/ and http://127.0.0.1:8000/accounts/logout/ already allow us to sign in and log out. However, if we successfully sign in, we end up at the unknown url http://127.0.0.1:8000/accounts/profile/. That is because allauth builds on Django's LoginView, which redirects to /accounts/profile/ after login. Since allauth doesn't provide a template for that, we are going to create that ourselves below. First some preparations.

All account templates for allauth should go into the directory account/ of your app, in our case userauth/templates/userauth/account/, so create this directory.

Make sure you have added the path userauth/templates/userauth/ to TEMPLATES in your settings file. Be careful: the directory with the templates is called account/, while the url's have an extra s: /accounts/…/. So the url …/accounts/login/ uses the template …/account/login.html.

All default allauth templates are here. Copy the template account/logout.html and put it in our own account/ folder. Modify the first paragraph into

<p>{% trans 'Are you ABSOLUTELY sure you want to sign out?' %}</p>

and visit http://127.0.0.1:8000/accounts/logout/ (sign in first if necessary), to check that our app now uses our own template.

Just a note on translation: all allauth templates are multilingual by default, i.e. they use the template tags trans loaded with {% load i18n %}. We will also do this throughout our own templates.

Now it is time to make our templates somewhat nicer; we will use Bootstrap for that. Go to the file base.html in your project templates folder. Copy the link to Bootstrap's CSS file and add it at the designated point in your base.html file. Also add the Javascript links near the end of your base.html template as explained.

In this tutorial (but feel free to use your own creativity!) we will use the Bootstrap grid system combined with Bootstrap cards with headers and footers. This allows our templates to respond to the width of our viewport. Using cards will allow us to put different parts of the templates in the header, the body or the footer of the card. Create a template base_card.html that does this, with the following content:

{% extends 'base.html' %}

{% block content %}

<div class="container">
    <div class="row justify-content-center">
        <div class="col-lg-8 col-md-10 col-sm-12">
            <div class="card">
                <div class="card-header">
                    {% block card-header %}{% endblock %}
                </div>
                <div class="card-body">
                    {% block card-body %}{% endblock %}
                </div>
                <div class="card-footer text-muted text-center">
                    {% block card-footer %}{% endblock %}
                </div>
           </div>
        </div>
    </div>
</div>

{% endblock %}

With a few modifications in the logout.html file we copied, we use the self-created blocks card-header and card-body, as follows:

{% extends 'account/base_card.html' %}

{% load i18n %}

{% block title %}{% trans "Sign Out" %}{% endblock %}

{% block card-header %}
    <h3>{% trans "Sign Out" %}</h3>
{% endblock %}

{% block card-body %}

    <p>{% trans "Are you sure you want to sign out?" %}</p>
    
    <form method="POST" action="{% url 'account_logout' %}">
        {% csrf_token %}
        <button type="submit" class="btn btn-outline-primary btn-sm">{% trans "Sign Out" %}</button>
    </form>
    
    <br><p>{% trans "No, stay logged in" %}</p>
    <a href="/" class="btn btn-outline-primary">{% trans "Return to site" %}</a>

{% endblock %}

Check out how our logout page looks now, at /accounts/logout/.

Let's now return to our missing template at /accounts/profile/. Within your app (userauth) create a urls.py file with the following content:

from django.urls import path
from .views import profile_view

urlpatterns = [
    path('profile/', profile_view, name='account_profile'),
]

And add the following to the url patterns of our project urls.py file:

path('accounts/', include('userauth.urls')),

to make our profile available at the url /accounts/profile/. Add to the views.py file:

def profile_view(request):
    return render(request, 'account/profile.html')

The only thing we need to do now is to create the template profile.html in our templates folder userauth/templates/userauth/account/. Create the file and add the following content:

{% extends 'account/base_card.html' %}

{% load i18n static %}

{% block title %}{% trans "Profile" %}{% endblock %}

{% block card-header %}
    <h3>{% trans "Account profile" %}</h3>
{% endblock %}

{% block card-body %}

    <div class="container">
       <div class="row">
            <div class="col border">
                <small>{% trans "First name" %}:</small><br>
                {{ request.user.first_name|default:'' }}
            </div>
            <div class="col border">
                <small>{% trans "Last name" %}:</small><br>
                {{ request.user.last_name|default:'' }}
            </div>
        </div>
    </div>

{% endblock %}

Note the |default. When fields are undefined, the value None is displayed in the template. To prevent this, we use Django's filter default, which displays nothing (an empty string).

Now if we successfully sign in, we are redirected to this profile page we just created. Obviously this is a very simple template, with only first name and last name. We can add all other user fields to our template as well, check the repository for the full profile.html.

We might as well set profile.html as our default landing page after a new user has been created. To do this, add the get_absolute_url method in your user model:

def get_absolute_url(self):
    return reverse('account_profile')

These are the basics to set up allauth and its templates. Read on if you want to embellish allauth's forms (such as sign in / sign up), set up email verification on signup, or use social accounts for signing in.

Comment on this article (sign in first or confirm by name and email below)