Django Registration
Introduction
User registration is a fundamental feature of most web applications. It allows users to create accounts, access personalized features, and maintain their profiles. Django, being a comprehensive web framework, provides robust tools for implementing user registration systems.
In this tutorial, we'll learn how to build a complete registration system in Django that allows users to:
- Create new accounts
- Receive verification emails
- Verify their email addresses
- Log in to their newly created accounts
By the end of this guide, you'll understand the core concepts of user registration in Django and be able to implement a secure registration system in your own applications.
Prerequisites
Before we begin, make sure you have:
- Basic knowledge of Django models, views, and templates
- A Django project already set up
- Understanding of basic HTML and forms
Setting Up User Registration
Step 1: Configure the User Model
Django comes with a built-in User model that handles authentication. For most applications, this model provides everything needed for registration and authentication. Let's start by ensuring our settings are properly configured.
In your settings.py
file, make sure you have the authentication apps included:
INSTALLED_APPS = [
# Django built-in apps
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
# Your apps
'your_app_name',
]
Step 2: Create a Registration Form
We need a form to collect user information. Django provides a UserCreationForm
that we can extend for our needs:
# forms.py
from django import forms
from django.contrib.auth.forms import UserCreationForm
from django.contrib.auth.models import User
class RegistrationForm(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
This form extends Django's built-in UserCreationForm
to include an email field, which isn't required by default.
Step 3: Create Registration Views
Next, we'll create views to handle the registration process:
# views.py
from django.shortcuts import render, redirect
from django.contrib.auth import login, authenticate
from .forms import RegistrationForm
from django.contrib.sites.shortcuts import get_current_site
from django.template.loader import render_to_string
from django.utils.http import urlsafe_base64_encode, urlsafe_base64_decode
from django.utils.encoding import force_bytes, force_str
from django.core.mail import EmailMessage
from .tokens import account_activation_token
from django.contrib.auth.models import User
def register(request):
if request.method == 'POST':
form = RegistrationForm(request.POST)
if form.is_valid():
user = form.save(commit=False)
user.is_active = False # Deactivate account till it is confirmed
user.save()
# Send an email to the user with the token:
current_site = get_current_site(request)
mail_subject = 'Activate your account.'
message = render_to_string('registration/account_activation_email.html', {
'user': user,
'domain': current_site.domain,
'uid': urlsafe_base64_encode(force_bytes(user.pk)),
'token': account_activation_token.make_token(user),
})
to_email = form.cleaned_data.get('email')
email = EmailMessage(
mail_subject, message, to=[to_email]
)
email.send()
return render(request, 'registration/register_confirm.html')
else:
form = RegistrationForm()
return render(request, 'registration/register.html', {'form': form})
def activate(request, uidb64, token):
try:
uid = force_str(urlsafe_base64_decode(uidb64))
user = User.objects.get(pk=uid)
except(TypeError, ValueError, OverflowError, User.DoesNotExist):
user = None
if user is not None and account_activation_token.check_token(user, token):
user.is_active = True
user.save()
login(request, user)
return render(request, 'registration/activation_successful.html')
else:
return render(request, 'registration/activation_invalid.html')
Step 4: Create a Token Generator
Create a new file called tokens.py
for the account activation token:
# tokens.py
from django.contrib.auth.tokens import PasswordResetTokenGenerator
class TokenGenerator(PasswordResetTokenGenerator):
def _make_hash_value(self, user, timestamp):
return (
str(user.pk) + str(timestamp) + str(user.is_active)
)
account_activation_token = TokenGenerator()
This token generator creates unique tokens for email verification.
Step 5: Create Templates for Registration
Now let's create the necessary templates:
register.html
{% extends 'base.html' %}
{% block content %}
<div class="registration-form">
<h2>Register</h2>
<form method="post">
{% csrf_token %}
<div class="form-group">
{{ form.as_p }}
</div>
<button type="submit" class="btn btn-primary">Register</button>
</form>
<p>Already have an account? <a href="{% url 'login' %}">Login</a></p>
</div>
{% endblock %}
register_confirm.html
{% extends 'base.html' %}
{% block content %}
<div class="register-confirm">
<h2>Account Registration</h2>
<p>
We have sent an email with instructions to activate your account.
Please check your inbox and follow the instructions to complete registration.
</p>
</div>
{% endblock %}
account_activation_email.html
{% autoescape off %}
Hi {{ user.username }},
Please click on the link below to confirm your registration:
http://{{ domain }}{% url 'activate' uidb64=uid token=token %}
If you did not make this request, you can simply ignore this email.
{% endautoescape %}
activation_successful.html
{% extends 'base.html' %}
{% block content %}
<div class="activation-successful">
<h2>Account Activated!</h2>
<p>
Your account has been successfully activated! You are now logged in.
</p>
<a href="{% url 'home' %}" class="btn btn-primary">Go to Homepage</a>
</div>
{% endblock %}
activation_invalid.html
{% extends 'base.html' %}
{% block content %}
<div class="activation-invalid">
<h2>Activation Failed</h2>
<p>
The activation link is invalid or has expired.
Please try registering again or contact support if you need assistance.
</p>
<a href="{% url 'register' %}" class="btn btn-primary">Register Again</a>
</div>
{% endblock %}
Step 6: Set Up URLs
Let's configure our URLs:
# urls.py
from django.urls import path
from . import views
urlpatterns = [
path('register/', views.register, name='register'),
path('activate/<uidb64>/<token>/', views.activate, name='activate'),
]
Step 7: Configure Email Settings
To make email sending work, configure your email settings in settings.py
:
# For development (prints emails to console)
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
# For production (example with Gmail)
"""
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_HOST = 'smtp.gmail.com'
EMAIL_PORT = 587
EMAIL_USE_TLS = True
EMAIL_HOST_USER = '[email protected]'
EMAIL_HOST_PASSWORD = 'your-password-or-app-password'
"""
Creating a Simple Registration Without Email Verification
For simpler applications, you might want to implement registration without email verification. Here's how:
# views.py - simplified version
def register_simple(request):
if request.method == 'POST':
form = RegistrationForm(request.POST)
if form.is_valid():
user = form.save()
# Log the user in immediately 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') # Redirect to home page
else:
form = RegistrationForm()
return render(request, 'registration/register.html', {'form': form})
Customizing the User Model
Django's built-in User model might not always fit your needs. If you need additional fields for registration, it's best to use a custom user model or create a profile model:
Option 1: User Profile Model
# models.py
from django.db import models
from django.contrib.auth.models import User
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)
location = models.CharField(max_length=30, blank=True)
birth_date = models.DateField(null=True, blank=True)
def __str__(self):
return self.user.username
@receiver(post_save, sender=User)
def create_user_profile(sender, instance, created, **kwargs):
if created:
Profile.objects.create(user=instance)
@receiver(post_save, sender=User)
def save_user_profile(sender, instance, **kwargs):
instance.profile.save()
Option 2: Custom User Model (recommended)
First, create a custom user model:
# models.py
from django.db import models
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)
Then, in your settings.py
, specify the custom user model:
AUTH_USER_MODEL = 'your_app_name.CustomUser'
And create a registration form for this custom user:
# forms.py
from django import forms
from django.contrib.auth.forms import UserCreationForm
from .models import CustomUser
class CustomUserCreationForm(UserCreationForm):
class Meta:
model = CustomUser
fields = ('username', 'email', 'birth_date', 'password1', 'password2')
Security Best Practices
When implementing registration, consider these security best practices:
- Password Validation: Django's
UserCreationForm
includes strong password validation by default - HTTPS: Always use HTTPS for registration/login forms
- CSRF Protection: Django includes CSRF protection by default; ensure it's not disabled
- Rate Limiting: Implement rate limiting for registration attempts
- Captcha: Consider adding captcha for registration to prevent spam
- Email Verification: Verify user emails before activating accounts
Here's how to implement a simple rate limiter:
# views.py with rate limiting
from django.core.cache import cache
from django.http import HttpResponse
def register_with_rate_limit(request):
# Get client IP
client_ip = get_client_ip(request)
# Check if IP is rate limited
if cache.get(f"registration_limit_{client_ip}"):
return HttpResponse("Too many registration attempts. Please try again later.", status=429)
if request.method == 'POST':
# Process form
# If form is not valid or spam is detected, increment rate limiting
attempts = cache.get(f"registration_attempts_{client_ip}", 0)
cache.set(f"registration_attempts_{client_ip}", attempts + 1, 3600) # One hour expiry
# If too many attempts, rate limit
if attempts >= 5:
cache.set(f"registration_limit_{client_ip}", True, 3600 * 24) # 24 hour ban
return HttpResponse("Too many failed attempts. Try again tomorrow.", status=429)
# Continue with regular registration logic
# ...
def get_client_ip(request):
x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
if x_forwarded_for:
ip = x_forwarded_for.split(',')[0]
else:
ip = request.META.get('REMOTE_ADDR')
return ip
Real-World Example: User Registration with Profile and Avatar
Here's a more comprehensive example for a social network site:
# models.py
from django.db import models
from django.contrib.auth.models import User
class UserProfile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, related_name='profile')
avatar = models.ImageField(upload_to='avatars/', default='avatars/default.png')
bio = models.TextField(max_length=500, blank=True)
website = models.URLField(max_length=200, blank=True)
location = models.CharField(max_length=100, blank=True)
birth_date = models.DateField(null=True, blank=True)
def __str__(self):
return f"{self.user.username}'s profile"
# forms.py
from django import forms
from django.contrib.auth.forms import UserCreationForm
from django.contrib.auth.models import User
from .models import UserProfile
class ExtendedUserCreationForm(UserCreationForm):
email = forms.EmailField(required=True)
first_name = forms.CharField(max_length=30)
last_name = forms.CharField(max_length=30)
class Meta:
model = User
fields = ('username', 'email', 'first_name', 'last_name', 'password1', 'password2')
class UserProfileForm(forms.ModelForm):
class Meta:
model = UserProfile
fields = ('avatar', 'bio', 'website', 'location', 'birth_date')
widgets = {
'birth_date': forms.DateInput(attrs={'type': 'date'}),
}
# views.py
def register_with_profile(request):
if request.method == 'POST':
user_form = ExtendedUserCreationForm(request.POST)
profile_form = UserProfileForm(request.POST, request.FILES)
if user_form.is_valid() and profile_form.is_valid():
user = user_form.save()
# Create user profile
profile = profile_form.save(commit=False)
profile.user = user
profile.save()
# Log user in
username = user_form.cleaned_data.get('username')
password = user_form.cleaned_data.get('password1')
user = authenticate(username=username, password=password)
login(request, user)
return redirect('profile')
else:
user_form = ExtendedUserCreationForm()
profile_form = UserProfileForm()
context = {
'user_form': user_form,
'profile_form': profile_form
}
return render(request, 'registration/register_with_profile.html', context)
Summary
In this tutorial, we've covered:
- Setting up Django's user authentication system
- Creating registration forms and views
- Implementing email verification
- Setting up templates for the registration process
- Creating a custom user model or profile
- Adding security measures like rate limiting
- Building a real-world example with user profiles
User registration is a critical feature for many web applications, and Django provides powerful tools to implement it securely and efficiently. By following the steps in this guide, you should now be able to implement a robust registration system in your Django project.
Additional Resources and Exercises
Resources
- Django Authentication Documentation
- Django Registration Package
- Django All-Auth - For social authentication
Exercises
-
Basic Exercise: Implement a simple registration system without email verification.
-
Intermediate Exercise: Add email verification to your registration system.
-
Advanced Exercise: Create a registration system with:
- Social authentication (Google, Facebook)
- Custom user model
- Profile picture upload
- Password strength meter on the frontend
-
Challenge: Build a complete authentication system with:
- Registration with email verification
- Password reset functionality
- Account deletion
- Two-factor authentication
By completing these exercises, you'll gain practical experience with Django's authentication system and be ready to implement sophisticated registration flows in your projects.
If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)