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:
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:
python manage.py startapp users
Then add it to your INSTALLED_APPS
:
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
:
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
:
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
:
{% 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
:
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
:
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
:
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
:
{% 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
:
{% 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:
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
:
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
:
# 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
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
:
path('profile/', views.profile, name='profile')
Create a Simple Profile Template
Create users/templates/users/profile.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
:
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
:
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
:
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:
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:
@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
:
{% 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:
- Setting up the authentication system
- User registration with custom forms
- Login and logout functionality
- Password management (reset, change)
- Protecting views with login requirements
- 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:
-
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
-
Password Management:
- Implement password reset functionality in your Django app
- Add a password change page for logged-in users
-
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
-
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! :)