When using Django’s built-in authentication system we create a separate Django Data Models (or apps) to manage this. For example, we might create a folder called accounts/ that will be in charge of all authentication.

Auth URLs

In accounts/urls.py we can include the following:

from django.urls import path, include
from django.contrib.auth import urls as auth_urls
 
app_name = "accounts"
urlpatterns = [
    path("", include(auth_urls)),
]

Here the path call includes the default patterns for account-related pages, such as login, password reset, etc. Adding custom pages for profiles and other account-related items would have their URLs defined here as well.

When making this addition, we must also update the main app urls.py file to include the auth file:

from django.urls import path, include
from django.contrib import admin
from django.core.handlers.wsgi import WSGIHandler
 
urlpatterns = [
    path("admin/", admin.site.urls),
    path("accounts/", include("accounts.urls")),
    path("", include("blogs.urls")),
]
 
application = WSGIHandler()

Login settings

In addition to creating the accounts app, we have to register the app as an installed app in settings.py:

INSTALLED_APPS=[
...
    "accounts",
...
]

This is how we tell Django to look for an accounts/ directory when finding URLs and templates.

We also have to include the following variable at the end of the settings file: LOGIN_REDIRECT_URL = "blogs:index". This allows Django to redirect users to the URL pattern named index if login was successful.

Templates

Although Django takes care of most of the background logic for authentication work we still have to include our own template for a login page. For example, we may create a file called login.html, located at accounts/templates/registration/login.html.

Note

In Django Organization we saved templates in a pattern like _blogs/templates/blogs_. When rendering registration-focused pages, however, Django looks for a template dir called registration/

In the login.html file we can still extend our blogs/base.html template to ensure consistent styling:

{% extends "blogs/base.html" %}
 
{% block content %}
 
  {% if form.errors %}
    <p>Your username and password didn't match. Please try again.</p>
  {% endif %}
 
  <form action="{% url 'accounts:login' %}" method='post'>
    {% csrf_token %}
    {{ form.as_div }}
 
    <button name="submit">Log in</button>
  </form>
  
{% endblock content %}

With this in place, we can also add the following logic to our base.html template:

  {% if user.is_authenticated %}
    <span class="is-vertical-align">
      Hello, {{ user.username }}.</span>
 
    <form action="{% url 'accounts:logout' %}" method="post"
        class="is-vertical-align">
      {% csrf_token %}
      <button class="button outline">Log out</button>
    </form>
 
  {% else %}
    <a href="{% url 'accounts:login' %}">Log in</a>
  {% endif %}

Info

Django templates automatically receive a user object, which has several properties such as is_authenticated.

Note

Django uses csrf_token to prevent cross-site forgery attacks, and it is a token required in all forms. As a result, we have to also add the CSRF token middleware in settings.py