Skip to main content

Django User Model

Introduction

Django comes with a powerful built-in authentication system that handles user accounts, groups, permissions, and cookie-based user sessions. At the core of this system is the User model, which provides essential functionality for user authentication and management in your Django applications.

The Django User model is part of the django.contrib.auth package and offers a secure way to manage user accounts without having to build authentication from scratch. Understanding this model is crucial for building secure web applications in Django.

The Default User Model

Django's default User model is located in django.contrib.auth.models and includes basic fields that most web applications need for user management:

  • username - Required. 150 characters or fewer. Letters, digits, and @/./+/-/_ only.
  • password - Required. A hash of the user's password (Django never stores raw passwords).
  • email - Optional. Email address.
  • first_name - Optional. User's first name.
  • last_name - Optional. User's last name.
  • is_active - Boolean. Designates whether this user account should be considered active.
  • is_staff - Boolean. Designates whether the user can access the admin site.
  • is_superuser - Boolean. Designates that this user has all permissions without explicitly assigning them.
  • date_joined - Date and time when the account was created.
  • last_login - Date and time of last login.

Basic Usage of the User Model

Let's see how to interact with the User model:

python
from django.contrib.auth.models import User

# Creating a new user
user = User.objects.create_user(
username='johndoe',
email='[email protected]',
password='secure_password123'
)

# Accessing user attributes
print(user.username) # Output: johndoe
print(user.email) # Output: [email protected]
print(user.is_active) # Output: True

# Checking if a user is authenticated
if user.is_authenticated:
print("User is authenticated")

# Creating a superuser (programmatically)
admin_user = User.objects.create_superuser(
username='admin',
email='[email protected]',
password='admin_password123'
)

# Updating user information
user.first_name = 'John'
user.last_name = 'Doe'
user.save()

# Checking passwords
correct_password = user.check_password('secure_password123') # Returns True
wrong_password = user.check_password('wrong_password') # Returns False

Creating a Superuser from the Command Line

You can also create a superuser using Django's management commands:

bash
python manage.py createsuperuser

This command will prompt you for a username, email address, and password.

Customizing the User Model

While Django's default User model works well for many projects, you may need to customize it for your specific requirements. There are several ways to extend or customize the User model:

Django recommends using a custom user model for all new projects, even if you're satisfied with the default User model. This gives you the flexibility to make changes to your user model in the future.

First, create a new model in your app's models.py:

python
# myapp/models.py
from django.contrib.auth.models import AbstractUser
from django.db import models

class CustomUser(AbstractUser):
# Add custom fields here
bio = models.TextField(max_length=500, blank=True)
birth_date = models.DateField(null=True, blank=True)
profile_picture = models.ImageField(upload_to='profile_pics/', null=True, blank=True)

def __str__(self):
return self.username

Then, tell Django to use this model as the default user model in your settings.py:

python
# settings.py
AUTH_USER_MODEL = 'myapp.CustomUser'

Finally, create a custom form for user creation and update:

python
# myapp/forms.py
from django import forms
from django.contrib.auth.forms import UserCreationForm, UserChangeForm
from .models import CustomUser

class CustomUserCreationForm(UserCreationForm):
class Meta:
model = CustomUser
fields = ('username', 'email', 'bio', 'birth_date')

class CustomUserChangeForm(UserChangeForm):
class Meta:
model = CustomUser
fields = ('username', 'email', 'bio', 'birth_date', 'profile_picture')

2. Using AbstractBaseUser for Complete Customization

For even more control, you can use AbstractBaseUser to create a user model from scratch:

python
# myapp/models.py
from django.contrib.auth.models import AbstractBaseUser, PermissionsMixin, BaseUserManager
from django.db import models
from django.utils import timezone

class CustomUserManager(BaseUserManager):
def create_user(self, email, username, password=None, **extra_fields):
if not email:
raise ValueError('Users must have an email address')
email = self.normalize_email(email)
user = self.model(email=email, username=username, **extra_fields)
user.set_password(password)
user.save(using=self._db)
return user

def create_superuser(self, email, username, password=None, **extra_fields):
extra_fields.setdefault('is_staff', True)
extra_fields.setdefault('is_superuser', True)

return self.create_user(email, username, password, **extra_fields)

class CustomUser(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(unique=True)
username = models.CharField(max_length=30, unique=True)
first_name = models.CharField(max_length=30, blank=True)
last_name = models.CharField(max_length=30, blank=True)
is_active = models.BooleanField(default=True)
is_staff = models.BooleanField(default=False)
date_joined = models.DateTimeField(default=timezone.now)

# Custom fields
bio = models.TextField(blank=True)

objects = CustomUserManager()

USERNAME_FIELD = 'email' # Use email as the unique identifier
REQUIRED_FIELDS = ['username'] # Required fields for createsuperuser

def __str__(self):
return self.email

def get_full_name(self):
return f'{self.first_name} {self.last_name}'

def get_short_name(self):
return self.first_name

3. Using OneToOneField with the Default User Model

If you don't want to replace the default User model but still need to store additional user data, you can create a profile model with a one-to-one relationship to the User model:

python
# myapp/models.py
from django.contrib.auth.models import User
from django.db import models
from django.db.models.signals import post_save
from django.dispatch import receiver

class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
bio = models.TextField(max_length=500, blank=True)
birth_date = models.DateField(null=True, blank=True)
profile_picture = models.ImageField(upload_to='profile_pics/', null=True, blank=True)

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

# Automatically create or update Profile when User is created or updated
@receiver(post_save, sender=User)
def create_or_update_user_profile(sender, instance, created, **kwargs):
if created:
Profile.objects.create(user=instance)
else:
instance.profile.save()

Authentication Views and Templates

Django provides pre-built views for handling common authentication tasks. Here's how to use them:

Setting Up Authentication URLs

First, include Django's authentication URLs in your project's urls.py:

python
# project/urls.py
from django.urls import path, include

urlpatterns = [
# Other URL patterns...
path('accounts/', include('django.contrib.auth.urls')),
]

This includes URLs for login, logout, password change, and password reset, such as:

  • /accounts/login/
  • /accounts/logout/
  • /accounts/password_change/
  • /accounts/password_reset/

Creating Authentication Templates

Django's auth views look for templates in specific locations. Create these templates in your project:

templates/
├── base.html
└── registration/
├── login.html
├── password_change_form.html
├── password_change_done.html
├── password_reset_form.html
├── password_reset_done.html
├── password_reset_confirm.html
└── password_reset_complete.html

Example of a basic login template:

html
<!-- templates/registration/login.html -->
{% extends 'base.html' %}

{% block content %}
<h2>Login</h2>
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">Login</button>
</form>
<p><a href="{% url 'password_reset' %}">Forgot password?</a></p>
<p>Don't have an account? <a href="{% url 'register' %}">Register here</a></p>
{% endblock %}

Creating a User Registration View

Django's auth doesn't include a registration view, so you'll need to create one:

python
# myapp/views.py
from django.contrib.auth import login, authenticate
from django.shortcuts import render, redirect
from django.contrib.auth.forms import UserCreationForm

def register(request):
if request.method == 'POST':
form = UserCreationForm(request.POST)
if form.is_valid():
user = form.save()
# Log in the user after registration
username = form.cleaned_data.get('username')
raw_password = form.cleaned_data.get('password1')
user = authenticate(username=username, password=raw_password)
login(request, user)
return redirect('home')
else:
form = UserCreationForm()
return render(request, 'registration/register.html', {'form': form})

Add the registration URL:

python
# myapp/urls.py
from django.urls import path
from . import views

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

And create a registration template:

html
<!-- templates/registration/register.html -->
{% extends 'base.html' %}

{% block content %}
<h2>Register</h2>
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">Sign Up</button>
</form>
<p>Already have an account? <a href="{% url 'login' %}">Login here</a></p>
{% endblock %}

Protecting Views with Authentication

Django provides decorators and mixins to restrict access to views:

Using the @login_required Decorator

python
from django.contrib.auth.decorators import login_required

@login_required
def profile_view(request):
return render(request, 'profile.html', {'user': request.user})

Using Class-Based View Mixins

python
from django.contrib.auth.mixins import LoginRequiredMixin
from django.views.generic import TemplateView

class ProfileView(LoginRequiredMixin, TemplateView):
template_name = 'profile.html'
login_url = '/accounts/login/' # Optional: custom login URL

def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['user'] = self.request.user
return context

Real-World Example: User Profile Management System

Let's build a complete user profile system that includes:

  1. Custom user model
  2. Registration, login, and logout
  3. Profile editing
  4. Password changing

Step 1: Create a Custom User Model

python
# accounts/models.py
from django.contrib.auth.models import AbstractUser
from django.db import models

class CustomUser(AbstractUser):
bio = models.TextField(blank=True)
location = models.CharField(max_length=100, blank=True)
birth_date = models.DateField(null=True, blank=True)
profile_picture = models.ImageField(upload_to='profile_pics/', null=True, blank=True)

def __str__(self):
return self.username

Step 2: Configure Settings

python
# settings.py
AUTH_USER_MODEL = 'accounts.CustomUser'

# Add to INSTALLED_APPS if not already included
INSTALLED_APPS = [
# ...
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
# ...
'accounts',
]

Step 3: Create Forms

python
# accounts/forms.py
from django import forms
from django.contrib.auth.forms import UserCreationForm, UserChangeForm
from .models import CustomUser

class CustomUserCreationForm(UserCreationForm):
class Meta:
model = CustomUser
fields = ('username', 'email', 'bio', 'location', 'birth_date')

class CustomUserChangeForm(UserChangeForm):
password = None # Remove password field from form

class Meta:
model = CustomUser
fields = ('username', 'email', 'first_name', 'last_name', 'bio',
'location', 'birth_date', 'profile_picture')
widgets = {
'birth_date': forms.DateInput(attrs={'type': 'date'}),
}

Step 4: Create Views

python
# accounts/views.py
from django.shortcuts import render, redirect
from django.contrib.auth import login, authenticate
from django.contrib.auth.decorators import login_required
from .forms import CustomUserCreationForm, CustomUserChangeForm
from django.contrib import messages

def register(request):
if request.method == 'POST':
form = CustomUserCreationForm(request.POST)
if form.is_valid():
user = form.save()
raw_password = form.cleaned_data.get('password1')
user = authenticate(username=user.username, password=raw_password)
login(request, user)
messages.success(request, 'Account created successfully!')
return redirect('profile')
else:
form = CustomUserCreationForm()
return render(request, 'registration/register.html', {'form': form})

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

@login_required
def edit_profile(request):
if request.method == 'POST':
form = CustomUserChangeForm(request.POST, request.FILES, instance=request.user)
if form.is_valid():
form.save()
messages.success(request, 'Your profile was successfully updated!')
return redirect('profile')
else:
form = CustomUserChangeForm(instance=request.user)
return render(request, 'accounts/edit_profile.html', {'form': form})

Step 5: Create URLs

python
# accounts/urls.py
from django.urls import path, include
from . import views

urlpatterns = [
path('', include('django.contrib.auth.urls')),
path('register/', views.register, name='register'),
path('profile/', views.profile, name='profile'),
path('profile/edit/', views.edit_profile, name='edit_profile'),
]

# project/urls.py
from django.urls import path, include

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

Step 6: Create Templates

html
<!-- templates/accounts/profile.html -->
{% extends 'base.html' %}

{% block content %}
<div class="profile-container">
<h1>{{ user.username }}'s Profile</h1>

<div class="profile-info">
{% if user.profile_picture %}
<img src="{{ user.profile_picture.url }}" alt="Profile Picture" class="profile-picture">
{% else %}
<div class="profile-picture placeholder">{{ user.username|make_list|first|upper }}</div>
{% endif %}

<div class="user-details">
<p><strong>Username:</strong> {{ user.username }}</p>
<p><strong>Email:</strong> {{ user.email }}</p>
<p><strong>Name:</strong> {{ user.first_name }} {{ user.last_name }}</p>
{% if user.bio %}
<p><strong>Bio:</strong> {{ user.bio }}</p>
{% endif %}
{% if user.location %}
<p><strong>Location:</strong> {{ user.location }}</p>
{% endif %}
{% if user.birth_date %}
<p><strong>Birth Date:</strong> {{ user.birth_date }}</p>
{% endif %}
</div>
</div>

<div class="profile-actions">
<a href="{% url 'edit_profile' %}" class="btn btn-primary">Edit Profile</a>
<a href="{% url 'password_change' %}" class="btn btn-secondary">Change Password</a>
</div>
</div>
{% endblock %}
html
<!-- templates/accounts/edit_profile.html -->
{% extends 'base.html' %}

{% block content %}
<div class="edit-profile-container">
<h1>Edit Profile</h1>

<form method="post" enctype="multipart/form-data">
{% csrf_token %}
{{ form.as_p }}
<button type="submit" class="btn btn-primary">Save Changes</button>
<a href="{% url 'profile' %}" class="btn btn-secondary">Cancel</a>
</form>
</div>
{% endblock %}

Best Practices for User Management

  1. Always use a custom user model - Even if you don't need customization now, it's much easier to start with a custom model than to migrate to one later.

  2. Never store plain text passwords - Django handles password hashing by default. Always use the set_password() method or create_user() function.

  3. Use HTTPS - Always deploy authentication systems over HTTPS to prevent data being intercepted.

  4. Implement proper password policies - Consider using a package like django-password-validators to enforce strong password requirements.

  5. Handle authentication securely:

    • Use authenticate() instead of directly checking passwords
    • Set session cookies to secure and HTTP-only
    • Implement proper CSRF protection (Django does this by default)
  6. Use Django's permission system - For role-based access control, use Django's Groups and Permissions.

  7. Consider multi-factor authentication - For sensitive applications, consider adding packages like django-two-factor-auth.

Summary

Django's User model provides a solid foundation for authentication in your web applications. It includes essential fields like username, email, and password, along with useful methods for authentication.

While the default User model works well for many applications, Django recommends creating a custom User model for all new projects. This can be done by extending AbstractUser for minor customizations or AbstractBaseUser for complete control.

Django also provides built-in views and forms for common authentication tasks like login, logout, password change, and password reset. By following best practices for user authentication and management, you can build secure, user-friendly applications with Django's authentication system.

Additional Resources

  1. Django User Authentication Documentation
  2. Django Custom User Model
  3. Django Authentication Views
  4. Django REST Framework Authentication (for APIs)

Exercises

  1. Create a custom user model that uses email as the username field instead of a separate username.
  2. Implement a profile page that allows users to upload and crop profile pictures.
  3. Add social authentication (e.g., Google, Facebook) to your Django project using django-allauth.
  4. Create a user management dashboard for administrators that shows user activity statistics.
  5. Implement a password strength meter for the registration and password change forms.

Remember, authentication is a critical part of your application's security. When in doubt, rely on Django's built-in tools rather than creating custom solutions for sensitive operations like password management.



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