Skip to content

Chapter 9: User Authentication System

9.1 Django Authentication Framework

User Model

Django has a built-in powerful user authentication system with the User model at its core. The User model contains the following fields:

python
# Main fields of Django's built-in User model
class User(models.Model):
    username = models.CharField(max_length=150, unique=True)
    first_name = models.CharField(max_length=150, blank=True)
    last_name = models.CharField(max_length=150, blank=True)
    email = models.EmailField(blank=True)
    is_staff = models.BooleanField(default=False)  # Can access admin
    is_active = models.BooleanField(default=True)  # Is active
    is_superuser = models.BooleanField(default=False)  # Is superuser
    last_login = models.DateTimeField(blank=True, null=True)
    date_joined = models.DateTimeField(default=timezone.now)

Basic operations using the User model:

python
from django.contrib.auth.models import User
from django.contrib.auth import authenticate, login, logout

# Create user
user = User.objects.create_user(
    username='john',
    email='john@example.com',
    password='secret'
)

# Create superuser
superuser = User.objects.create_superuser(
    username='admin',
    email='admin@example.com',
    password='secret'
)

# Authenticate user
user = authenticate(username='john', password='secret')
if user is not None:
    print("User authentication successful")
else:
    print("Username or password incorrect")

# Modify user attributes
user.first_name = 'John'
user.last_name = 'Doe'
user.save()

# Set password
user.set_password('newpassword')
user.save()

# Check password
if user.check_password('newpassword'):
    print("Password correct")

Extending the User model:

python
# Method 1: One-to-one relationship (recommended)
from django.contrib.auth.models import User
from django.db import models

class UserProfile(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    bio = models.TextField(max_length=500, blank=True)
    location = models.CharField(max_length=30, blank=True)
    birth_date = models.DateField(null=True, blank=True)
    avatar = models.ImageField(upload_to='avatars/', blank=True)

# Signal handler to create user profile
from django.db.models.signals import post_save
from django.dispatch import receiver

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

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

# Method 2: Custom User model
from django.contrib.auth.models import AbstractUser

class CustomUser(AbstractUser):
    bio = models.TextField(max_length=500, blank=True)
    location = models.CharField(max_length=30, blank=True)
    birth_date = models.DateField(null=True, blank=True)

# Set in settings.py
AUTH_USER_MODEL = 'myapp.CustomUser'

Authentication Views

Django provides built-in authentication views to handle common authentication tasks:

python
# urls.py
from django.urls import path, include
from django.contrib.auth import views as auth_views

urlpatterns = [
    # Use Django's built-in authentication views
    path('accounts/', include('django.contrib.auth.urls')),
    
    # Or define each view separately
    path('login/', auth_views.LoginView.as_view(), name='login'),
    path('logout/', auth_views.LogoutView.as_view(), name='logout'),
    path('password_change/', auth_views.PasswordChangeView.as_view(), name='password_change'),
    path('password_change/done/', auth_views.PasswordChangeDoneView.as_view(), name='password_change_done'),
    path('password_reset/', auth_views.PasswordResetView.as_view(), name='password_reset'),
    path('password_reset/done/', auth_views.PasswordResetDoneView.as_view(), name='password_reset_done'),
    path('reset/<uidb64>/<token>/', auth_views.PasswordResetConfirmView.as_view(), name='password_reset_confirm'),
    path('reset/done/', auth_views.PasswordResetCompleteView.as_view(), name='password_reset_complete'),
]

Custom login view:

python
# views.py
from django.shortcuts import render, redirect
from django.contrib.auth import authenticate, login
from django.contrib.auth.forms import AuthenticationForm
from django.contrib import messages

def custom_login(request):
    if request.method == 'POST':
        form = AuthenticationForm(request, data=request.POST)
        if form.is_valid():
            username = form.cleaned_data.get('username')
            password = form.cleaned_data.get('password')
            user = authenticate(username=username, password=password)
            if user is not None:
                login(request, user)
                messages.info(request, f"Welcome, {username}!")
                return redirect('home')
            else:
                messages.error(request, "Username or password incorrect")
        else:
            messages.error(request, "Username or password incorrect")
    else:
        form = AuthenticationForm()
    
    return render(request, 'registration/login.html', {'form': form})

# Custom login template registration/login.html
"""
<form method="post">
    {% csrf_token %}
    {{ form.as_p }}
    <button type="submit">Login</button>
</form>
"""

Permission System

Django's permission system is based on the user, group, and permission model:

python
from django.contrib.auth.models import User, Group, Permission
from django.contrib.contenttypes.models import ContentType
from myapp.models import Article

# Create permission
content_type = ContentType.objects.get_for_model(Article)
permission = Permission.objects.create(
    codename='can_publish_article',
    name='Can Publish Article',
    content_type=content_type,
)

# Assign permission to user
user = User.objects.get(username='john')
user.user_permissions.add(permission)

# Assign permission to group
group = Group.objects.get(name='Editors')
group.permissions.add(permission)

# Add user to group
user.groups.add(group)

# Check user permission
if user.has_perm('myapp.can_publish_article'):
    print("User has permission to publish articles")

# Check if user belongs to a group
if user.groups.filter(name='Editors').exists():
    print("User is an editor")

# Check permission in views
from django.contrib.auth.decorators import permission_required

@permission_required('myapp.can_publish_article')
def publish_article(request):
    # Only users with publish permission can access
    pass

# Check permission in class-based views
from django.contrib.auth.mixins import PermissionRequiredMixin

class PublishArticleView(PermissionRequiredMixin, CreateView):
    permission_required = 'myapp.can_publish_article'
    # View implementation

Group Management

Groups are an effective way to manage user permissions:

python
from django.contrib.auth.models import Group, Permission
from django.contrib.contenttypes.models import ContentType

# Create groups
editors_group = Group.objects.create(name='Editors')
writers_group = Group.objects.create(name='Writers')

# Get permissions
content_type = ContentType.objects.get_for_model(Article)
add_article_perm = Permission.objects.get(
    content_type=content_type,
    codename='add_article'
)
change_article_perm = Permission.objects.get(
    content_type=content_type,
    codename='change_article'
)
delete_article_perm = Permission.objects.get(
    content_type=content_type,
    codename='delete_article'
)

# Assign permissions to group
editors_group.permissions.add(
    add_article_perm,
    change_article_perm,
    delete_article_perm
)

# Add user to group
user = User.objects.get(username='john')
user.groups.add(editors_group)

# Check if user belongs to group
if user.groups.filter(name='Editors').exists():
    print("User is an editor")

# Remove user from group
user.groups.remove(editors_group)

# Delete group
editors_group.delete()

Using permissions in templates:

html
<!-- Check if user is authenticated -->
{% if user.is_authenticated %}
    <p>Welcome, {{ user.username }}!</p>
    <a href="{% url 'logout' %}">Logout</a>
{% else %}
    <a href="{% url 'login' %}">Login</a>
{% endif %}

<!-- Check user permissions -->
{% if perms.myapp.add_article %}
    <a href="{% url 'article_create' %}">Create Article</a>
{% endif %}

<!-- Check if user belongs to specific groups -->
{% if user.groups.all %}
    <p>Your groups:
    {% for group in user.groups.all %}
        {{ group.name }}{% if not forloop.last %}, {% endif %}
    {% endfor %}
    </p>
{% endif %}

With Django's authentication framework, you can easily implement common authentication features such as user registration, login, and permission management.

Summary

Django's authentication framework provides a complete user management system:

  1. ✅ Built-in User model handles basic user information
  2. ✅ Supports extending User model to meet specific needs
  3. ✅ Built-in authentication views simplify login/logout processes
  4. ✅ Access control based on permissions and groups
  5. ✅ Permission checking in templates

Mastering the authentication framework is the foundation for building secure web applications.

Next

We will learn about the specific implementation of user registration and login.

9.2 User Registration →

Contents

Back to Course Outline

Released under the [BY-NC-ND License](https://creativecommons.org/licenses/by-nc-nd/4.0/deed.en).