Skip to main content

Django User Authentication

Authentication is a fundamental aspect of web applications, allowing you to identify users and restrict access to certain parts of your site. Django provides a robust authentication system out of the box, making it easy to handle user accounts, permissions, groups, and more.

Introduction to Django Authentication

Django's authentication system handles user accounts, groups, permissions, and cookie-based user sessions. It's designed to be secure and flexible, allowing you to:

  • Create new users and authenticate them
  • Assign permissions to users and groups
  • Manage user sessions
  • Handle password hashing and validation

The system includes built-in views for common operations like login, logout, and password management, along with forms and templates for these actions.

Setting Up Authentication

Django's authentication system is included by default when you create a new project. Let's look at what you need to ensure it's properly configured:

1. Verify your settings.py

Check that the authentication middleware and apps are included in your settings.py file:

python
INSTALLED_APPS = [
# ...
'django.contrib.auth',
'django.contrib.contenttypes',
# ...
]

MIDDLEWARE = [
# ...
'django.contrib.sessions.middleware.SessionMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
# ...
]

2. Create a Users App (Optional)

While not required, it's common practice to create a dedicated app for user-related functionality:

bash
python manage.py startapp users

Then add it to your INSTALLED_APPS:

python
INSTALLED_APPS = [
# ...
'users',
]

User Registration

Django doesn't provide built-in views for user registration, but it's easy to create one using Django's UserCreationForm.

Step 1: Create the Registration Form

In your users/forms.py:

python
from django import forms
from django.contrib.auth.forms import UserCreationForm
from django.contrib.auth.models import User

class CustomUserCreationForm(UserCreationForm):
email = forms.EmailField(required=True)

class Meta:
model = User
fields = ("username", "email", "password1", "password2")

def save(self, commit=True):
user = super().save(commit=False)
user.email = self.cleaned_data["email"]
if commit:
user.save()
return user

Step 2: Create the Registration View

In your users/views.py:

python
from django.shortcuts import render, redirect
from django.contrib.auth import login
from django.contrib import messages
from .forms import CustomUserCreationForm

def register(request):
if request.method == "POST":
form = CustomUserCreationForm(request.POST)
if form.is_valid():
user = form.save()
login(request, user)
messages.success(request, f"Account created for {user.username}!")
return redirect('home') # Redirect to your home page
else:
form = CustomUserCreationForm()

return render(request, "users/register.html", {"form": form})

Step 3: Create the Registration Template

Create users/templates/users/register.html:

html
{% extends "base.html" %}

{% block content %}
<div class="form-container">
<h2>Register</h2>
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">Sign Up</button>
</form>
<div class="border-top pt-3">
<small>
Already have an account? <a href="{% url 'login' %}">Log In</a>
</small>
</div>
</div>
{% endblock %}

Step 4: Add URL Pattern

In your users/urls.py:

python
from django.urls import path
from . import views

urlpatterns = [
path('register/', views.register, name='register'),
]

Then include this in your project's main urls.py:

python
from django.urls import path, include

urlpatterns = [
# ...
path('users/', include('users.urls')),
# ...
]

Login and Logout

Django provides built-in views for login and logout functionality.

Setting Up Login Views

Update your project's urls.py:

python
from django.contrib.auth import views as auth_views

urlpatterns = [
# ...
path('login/', auth_views.LoginView.as_view(template_name='users/login.html'), name='login'),
path('logout/', auth_views.LogoutView.as_view(template_name='users/logout.html'), name='logout'),
# ...
]

Create Login and Logout Templates

Create users/templates/users/login.html:

html
{% extends "base.html" %}

{% block content %}
<div class="form-container">
<h2>Login</h2>
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">Login</button>
</form>
<div class="border-top pt-3">
<small>
Need an account? <a href="{% url 'register' %}">Sign Up Now</a>
</small>
</div>
</div>
{% endblock %}

Create users/templates/users/logout.html:

html
{% extends "base.html" %}

{% block content %}
<div class="content-section">
<h2>You have been logged out</h2>
<div>
<small>
<a href="{% url 'login' %}">Log In Again</a>
</small>
</div>
</div>
{% endblock %}

Configure Login/Logout Redirects

In settings.py, add:

python
LOGIN_REDIRECT_URL = 'home'  # Redirect after successful login
LOGIN_URL = 'login' # URL to redirect to when login is required

Password Management

Django also provides built-in views for password-related operations:

Adding Password Reset URLs

In your project's urls.py:

python
urlpatterns = [
# ...
path('password-reset/',
auth_views.PasswordResetView.as_view(template_name='users/password_reset.html'),
name='password_reset'),
path('password-reset/done/',
auth_views.PasswordResetDoneView.as_view(template_name='users/password_reset_done.html'),
name='password_reset_done'),
path('password-reset-confirm/<uidb64>/<token>/',
auth_views.PasswordResetConfirmView.as_view(template_name='users/password_reset_confirm.html'),
name='password_reset_confirm'),
path('password-reset-complete/',
auth_views.PasswordResetCompleteView.as_view(template_name='users/password_reset_complete.html'),
name='password_reset_complete'),
# ...
]

Email Configuration for Password Reset

For password reset to work, you need to configure email settings in settings.py:

python
# Email settings for development
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'

# For production, use something like:
# EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
# EMAIL_HOST = 'smtp.example.com'
# EMAIL_PORT = 587
# EMAIL_USE_TLS = True
# EMAIL_HOST_USER = '[email protected]'
# EMAIL_HOST_PASSWORD = 'your_password'

Protecting Views with Login Requirements

To restrict access to certain views for logged-in users only:

Using the login_required Decorator

python
from django.contrib.auth.decorators import login_required

@login_required
def profile(request):
return render(request, 'users/profile.html')

Add this view to your urls.py:

python
path('profile/', views.profile, name='profile')

Create a Simple Profile Template

Create users/templates/users/profile.html:

html
{% extends "base.html" %}

{% block content %}
<div class="content-section">
<div class="media">
<div class="media-body">
<h2 class="account-heading">{{ user.username }}</h2>
<p class="text-secondary">{{ user.email }}</p>
</div>
</div>
</div>
{% endblock %}

Real-world Example: User Account Management System

Let's put everything together in a more comprehensive example of an account management system:

User Profile Model

In users/models.py:

python
from django.db import models
from django.contrib.auth.models import User
from PIL import Image

class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
image = models.ImageField(default='default.jpg', upload_to='profile_pics')
bio = models.TextField(max_length=500, blank=True)
location = models.CharField(max_length=30, blank=True)
birth_date = models.DateField(null=True, blank=True)

def __str__(self):
return f'{self.user.username} Profile'

def save(self, *args, **kwargs):
super().save(*args, **kwargs)

img = Image.open(self.image.path)

if img.height > 300 or img.width > 300:
output_size = (300, 300)
img.thumbnail(output_size)
img.save(self.image.path)

Create Signals for Profile Creation

In users/signals.py:

python
from django.db.models.signals import post_save
from django.contrib.auth.models import User
from django.dispatch import receiver
from .models import Profile

@receiver(post_save, sender=User)
def create_profile(sender, instance, created, **kwargs):
if created:
Profile.objects.create(user=instance)

@receiver(post_save, sender=User)
def save_profile(sender, instance, **kwargs):
instance.profile.save()

Update users/apps.py:

python
from django.apps import AppConfig

class UsersConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'users'

def ready(self):
import users.signals

Profile Update Forms

In users/forms.py, add:

python
from .models import Profile

class UserUpdateForm(forms.ModelForm):
email = forms.EmailField()

class Meta:
model = User
fields = ['username', 'email']

class ProfileUpdateForm(forms.ModelForm):
class Meta:
model = Profile
fields = ['image', 'bio', 'location', 'birth_date']

Update the Profile View

In users/views.py, update the profile view:

python
@login_required
def profile(request):
if request.method == 'POST':
u_form = UserUpdateForm(request.POST, instance=request.user)
p_form = ProfileUpdateForm(request.POST, request.FILES, instance=request.user.profile)

if u_form.is_valid() and p_form.is_valid():
u_form.save()
p_form.save()
messages.success(request, 'Your account has been updated!')
return redirect('profile')
else:
u_form = UserUpdateForm(instance=request.user)
p_form = ProfileUpdateForm(instance=request.user.profile)

context = {
'u_form': u_form,
'p_form': p_form
}

return render(request, 'users/profile.html', context)

Update the Profile Template

Update users/templates/users/profile.html:

html
{% extends "base.html" %}

{% block content %}
<div class="content-section">
<div class="media">
<img class="rounded-circle account-img" src="{{ user.profile.image.url }}">
<div class="media-body">
<h2 class="account-heading">{{ user.username }}</h2>
<p class="text-secondary">{{ user.email }}</p>
{% if user.profile.bio %}
<p>{{ user.profile.bio }}</p>
{% endif %}
{% if user.profile.location %}
<p><strong>Location:</strong> {{ user.profile.location }}</p>
{% endif %}
{% if user.profile.birth_date %}
<p><strong>Birth Date:</strong> {{ user.profile.birth_date }}</p>
{% endif %}
</div>
</div>

<form method="POST" enctype="multipart/form-data">
{% csrf_token %}
<fieldset class="form-group">
<legend class="border-bottom mb-4">Profile Info</legend>
{{ u_form.as_p }}
{{ p_form.as_p }}
</fieldset>
<div class="form-group">
<button class="btn btn-outline-info" type="submit">Update</button>
</div>
</form>
</div>
{% endblock %}

Summary

Django's built-in authentication system provides a comprehensive solution for managing users in your web applications. We've covered:

  1. Setting up the authentication system
  2. User registration with custom forms
  3. Login and logout functionality
  4. Password management (reset, change)
  5. Protecting views with login requirements
  6. Creating a complete user profile system

By leveraging Django's authentication framework, you can implement secure user authentication without having to build everything from scratch.

Additional Resources and Exercises

Resources:

Exercises:

  1. Basic Authentication Setup:

    • Create a new Django project with user registration, login, and logout functionality
    • Add a profile page that displays the user's information
  2. Password Management:

    • Implement password reset functionality in your Django app
    • Add a password change page for logged-in users
  3. Advanced Profile System:

    • Extend the user profile to include more details like social media handles
    • Add the ability for users to delete their accounts
    • Implement email verification for new user registrations
  4. Permission-Based Access:

    • Create different user groups (e.g., regular users, premium users, admins)
    • Restrict access to certain views based on group membership
    • Create a dashboard that shows different content based on user permissions

By completing these exercises, you'll gain practical experience with Django's authentication system and be able to implement secure user management in your applications.



If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)