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:
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:
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:
1. Using a Custom User Model (Recommended)
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
:
# 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
:
# settings.py
AUTH_USER_MODEL = 'myapp.CustomUser'
Finally, create a custom form for user creation and update:
# 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:
# 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:
# 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
:
# 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:
<!-- 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:
# 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:
# myapp/urls.py
from django.urls import path
from . import views
urlpatterns = [
path('register/', views.register, name='register'),
]
And create a registration template:
<!-- 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
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
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:
- Custom user model
- Registration, login, and logout
- Profile editing
- Password changing
Step 1: Create a Custom User Model
# 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
# 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
# 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
# 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
# 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
<!-- 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 %}
<!-- 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
-
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.
-
Never store plain text passwords - Django handles password hashing by default. Always use the
set_password()
method orcreate_user()
function. -
Use HTTPS - Always deploy authentication systems over HTTPS to prevent data being intercepted.
-
Implement proper password policies - Consider using a package like
django-password-validators
to enforce strong password requirements. -
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)
- Use
-
Use Django's permission system - For role-based access control, use Django's
Groups
andPermissions
. -
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
- Django User Authentication Documentation
- Django Custom User Model
- Django Authentication Views
- Django REST Framework Authentication (for APIs)
Exercises
- Create a custom user model that uses email as the username field instead of a separate username.
- Implement a profile page that allows users to upload and crop profile pictures.
- Add social authentication (e.g., Google, Facebook) to your Django project using
django-allauth
. - Create a user management dashboard for administrators that shows user activity statistics.
- 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! :)