Introduction
If you're looking to build a complete user management system using Django, this guide will walk you through the exact steps from setting up the environment to deploying your project online. By the end of this tutorial, you'll have a working app with user registration, profile management, logout functionality, admin control, and unit tests ready to be deployed to platforms like Render.
Let’s dive straight into the process.
Step-by-Step Guide
Step 1: Environment Setup
Goal: Set up the development environment and initialize the Django project.
Install Prerequisites:
Ensure Python 3.11+ is installed:
pip --version
python --version.
Create Virtual Environment:
python -m venv venv
source venv/bin/activate # On Windows: venv\Scripts\activate
Install Django:
pip install django
Create Django Project:
django-admin startproject user_management .
python manage.py startapp users
Configure Project:
Update user_management/settings.py to include the users app and authentication settings
Initialize Git:
git init
git add .
git commit -m "Initial project setup: Created Django project and users app with basic configuration"
Create a GitHub repository and push:
git remote add origin <your-repo-url>
git push -u origin main.
python manage.py runserver
Step 2: Create User Models
Goal: Define the UserProfile model for extended user information and verification.
Create Model:
Add the UserProfile model to users/models.py
from django.db import models
from django.contrib.auth.models import User
from django.utils.crypto import get_random_string
class UserProfile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
bio = models.TextField(blank=True)
verification_token = models.CharField(max_length=50, blank=True)
is_verified = models.BooleanField(default=False)
def generate_verification_token(self):
self.verification_token = get_random_string(50)
self.save()
return self.verification_token
def __str__(self):
return f"{self.user.username}'s profile"
This model includes fields for bio, verification token, and verification status.
Apply Migrations:
python manage.py makemigrations
python manage.py migrate
Register Model in Admin:
Create users/admin.py:
from django.contrib import admin
from .models import UserProfile
admin.site.register(UserProfile)
Commit Changes:
git add .
git commit -m "Added UserProfile model: Includes bio and verification fields with admin registration"
Step 3: Implement User Registration
Objective: Allow users to register with username, email, and password.
Create RegistrationForm in users/forms.py
from django import forms
from django.contrib.auth.models import User
from django.contrib.auth.forms import UserCreationForm, PasswordChangeForm
from .models import UserProfile
class RegistrationForm(UserCreationForm):
email = forms.EmailField(required=True)
class Meta:
model = User
fields = ['username', 'email', 'password1', 'password2']
class ProfileForm(forms.ModelForm):
class Meta:
model = UserProfile
fields = ['bio']
class UserUpdateForm(forms.ModelForm):
email = forms.EmailField()
class Meta:
model = User
fields = ['username', 'email']
Add register view in users/views.py
def register(request):
if request.method == 'POST':
form = RegistrationForm(request.POST)
if form.is_valid():
user = form.save()
UserProfile.objects.create(user=user).generate_verification_token()
login(request, user)
messages.success(request, 'Registration successful! Please verify your account.')
return redirect('verify')
else:
form = RegistrationForm()
return render(request, 'users/register.html', {'form': form})
Set up URLs
Add users/urls.py and include it in user_management/urls.py.
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('', include('users.urls')),
]
Create Templates
base.html, register.html, and login.html under templates/users/.
Test Registration
Run server and visit
Commit Changes
git add .
git commit -m "Implemented user registration: Added form, view, and templates for signup"
Step 4: Add Mock Email Verification
Objective: Use a token-based system to simulate email verification.
Add verify view in users/views.py
Create verify.html template
<!DOCTYPE html>
<html>
<head>
<title>{% block title %}User Management{% endblock %}</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
</head>
<body>
<nav class="navbar navbar-expand-lg navbar-light bg-primary">
<div class="container">
<a class="navbar-brand text-white" href="{% url 'profile' %}">User Management</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarNav">
<div class="navbar-nav ms-auto">
{% if user.is_authenticated %}
<a class="nav-link text-white" href="{% url 'profile' %}">Profile</a>
<a class="nav-link text-white" href="{% url 'change_password' %}">Change Password</a>
<a class="nav-link text-white" href="{% url 'logout' %}">Logout</a>
{% else %}
<a class="nav-link text-white" href="{% url 'register' %}">Register</a>
<a class="nav-link text-white" href="{% url 'login' %}">Login</a>
{% endif %}
</div>
</div>
</div>
</nav>
<div class="container mt-4">
{% if messages %}
{% for message in messages %}
<div class="alert alert-{{ message.tags }} alert-dismissible fade show" role="alert">
{{ message }}
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
</div>
{% endfor %}
{% endif %}
{% block content %}
{% endblock %}
</div>
<footer class="bg-primary text-white text-center py-3 fixed-bottom">
<div class="container">
<p class="mb-0">© 2025 User Management System. All rights reserved.</p>
</div>
</footer>
</body>
</html>
Retrieve Token
Test verification at
git add .
git commit -m "Added mock email verification: Implemented token-based verification with view and template"
Step 5: Implement Profile Management
Objective: Allow users to view/edit their profile and change passwords.
Update Forms and Views
ProfileForm and UserUpdateForm in users/forms.py
profile and change_password views in users/views.py
Create Templates
profile.html and change_password.html
<!DOCTYPE html>
<html>
<head>
<title>{% block title %}User Management{% endblock %}</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
</head>
<body>
<nav class="navbar navbar-expand-lg navbar-light bg-primary">
<div class="container">
<a class="navbar-brand text-white" href="{% url 'profile' %}">User Management</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarNav">
<div class="navbar-nav ms-auto">
{% if user.is_authenticated %}
<a class="nav-link text-white" href="{% url 'profile' %}">Profile</a>
<a class="nav-link text-white" href="{% url 'change_password' %}">Change Password</a>
<a class="nav-link text-white" href="{% url 'logout' %}">Logout</a>
{% else %}
<a class="nav-link text-white" href="{% url 'register' %}">Register</a>
<a class="nav-link text-white" href="{% url 'login' %}">Login</a>
{% endif %}
</div>
</div>
</div>
</nav>
<div class="container mt-4">
{% if messages %}
{% for message in messages %}
<div class="alert alert-{{ message.tags }} alert-dismissible fade show" role="alert">
{{ message }}
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
</div>
{% endfor %}
{% endif %}
{% block content %}
{% endblock %}
</div>
<footer class="bg-primary text-white text-center py-3 fixed-bottom">
<div class="container">
<p class="mb-0">© 2025 User Management System. All rights reserved.</p>
</div>
</footer>
</body>
</html>
{% extends 'users/base.html' %}
{% load widget_tweaks %}
{% block content %}
<div class="container py-5">
<div class="row justify-content-center">
<div class="col-md-6">
<div class="card shadow-sm">
<div class="card-body">
<h2 class="card-title text-center mb-4">Change Password</h2>
{% if messages %}
{% for message in messages %}
<div class="alert {% if message.tags %}alert-{{ message.tags }}{% else %}alert-info{% endif %} alert-dismissible fade show" role="alert">
{{ message }}
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
</div>
{% endfor %}
{% endif %}
<form method="post">
{% csrf_token %}
<div class="mb-3">
<label for="{{ form.old_password.id_for_label }}" class="form-label">Old Password</label>
{{ form.old_password|add_class:"form-control" }}
{% if form.old_password.errors %}
{% for error in form.old_password.errors %}
<div class="text-danger">{{ error }}</div>
{% endfor %}
{% endif %}
</div>
<div class="mb-3">
<label for="{{ form.new_password1.id_for_label }}" class="form-label">New Password</label>
{{ form.new_password1|add_class:"form-control" }}
{% if form.new_password1.errors %}
{% for error in form.new_password1.errors %}
<div class="text-danger">{{ error }}</div>
{% endfor %}
{% endif %}
</div>
<div class="mb-3">
<label for="{{ form.new_password2.id_for_label }}" class="form-label">Confirm New Password</label>
{{ form.new_password2|add_class:"form-control" }}
{% if form.new_password2.errors %}
{% for error in form.new_password2.errors %}
<div class="text-danger">{{ error }}</div>
{% endfor %}
{% endif %}
</div>
<div class="d-grid">
<button type="submit" class="btn btn-primary">Change Password</button>
</div>
</form>
<p class="text-center mt-3">
<a href="{% url 'profile' %}" class="btn btn-outline-primary">Back to Profile</a>
</p>
</div>
</div>
</div>
</div>
</div>
{% endblock %}
Test Locally
Access /profile/ and /change-password/ after login.
Commit Changes
git add .
git commit -m "Implemented profile management: Added view/edit profile and password change functionality"
Step 6: Configure Admin Panel
Objective: Allow admins to manage users and their profiles.
Create Superuser
python manage.py createsuperuser
Test Admin Dashboard
Commit Changes
git add .
git commit -m "Configured admin panel: Enabled user and profile management for admins"
Step 7: Write Unit Tests
Objective: Ensure your models and views work as expected.
Create Tests in users/tests.py
Run Tests
python manage.py test
git add .
git commit -m "Added unit tests: Implemented tests for UserProfile model and key views"
Conclusion
This guide provides a clean and structured approach to building a Django user management system from scratch. Each step from environment setup to deployment is modular and easy to follow. You can reuse or customize parts of this system for any Django-based project that requires user accounts.
Whether you're a beginner learning Django or a developer working on a deadline, these practical steps will help you build, test, and deploy with confidence.
Top comments (0)