DEV Community

SAINAPEI LENAPUNYA
SAINAPEI LENAPUNYA

Posted on

Day 6: Django User Management System: A Practical Guide to Building, Testing & Deploying

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.
Enter fullscreen mode Exit fullscreen mode

Create Virtual Environment:

python -m venv venv
source venv/bin/activate  # On Windows: venv\Scripts\activate
Enter fullscreen mode Exit fullscreen mode

Install Django:

pip install django

Enter fullscreen mode Exit fullscreen mode

Create Django Project:

django-admin startproject user_management .
python manage.py startapp users
Enter fullscreen mode Exit fullscreen mode

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"
Enter fullscreen mode Exit fullscreen mode

Create a GitHub repository and push:

git remote add origin <your-repo-url>
git push -u origin main.
Enter fullscreen mode Exit fullscreen mode


Results:
Run

python manage.py runserver
Enter fullscreen mode Exit fullscreen mode

Then Boom!!!

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"
Enter fullscreen mode Exit fullscreen mode

This model includes fields for bio, verification token, and verification status.
Apply Migrations:

python manage.py makemigrations
python manage.py migrate
Enter fullscreen mode Exit fullscreen mode

Register Model in Admin:
Create users/admin.py:

from django.contrib import admin
from .models import UserProfile

admin.site.register(UserProfile)
Enter fullscreen mode Exit fullscreen mode

Commit Changes:

git add .
git commit -m "Added UserProfile model: Includes bio and verification fields with admin registration"
Enter fullscreen mode Exit fullscreen mode

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']
Enter fullscreen mode Exit fullscreen mode

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})
Enter fullscreen mode Exit fullscreen mode

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')),
]
Enter fullscreen mode Exit fullscreen mode

Create Templates

base.html, register.html, and login.html under templates/users/.

Test Registration

Run server and visit

Register page: at .

Login page: at

Logout page: at

Commit Changes

git add .
git commit -m "Implemented user registration: Added form, view, and templates for signup"
Enter fullscreen mode Exit fullscreen mode

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">&copy; 2025 User Management System. All rights reserved.</p>
        </div>
    </footer>
</body>
</html>
Enter fullscreen mode Exit fullscreen mode

Retrieve Token
Test verification at


Commit Changes

git add .
git commit -m "Added mock email verification: Implemented token-based verification with view and template"
Enter fullscreen mode Exit fullscreen mode

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">&copy; 2025 User Management System. All rights reserved.</p>
        </div>
    </footer>
</body>
</html>
Enter fullscreen mode Exit fullscreen mode
{% 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 %}
Enter fullscreen mode Exit fullscreen mode

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"
Enter fullscreen mode Exit fullscreen mode

Step 6: Configure Admin Panel
Objective: Allow admins to manage users and their profiles.

Create Superuser

python manage.py createsuperuser

Enter fullscreen mode Exit fullscreen mode

Test Admin Dashboard

Visit and log in.

Commit Changes

git add .
git commit -m "Configured admin panel: Enabled user and profile management for admins"
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode


Commit Changes

git add .
git commit -m "Added unit tests: Implemented tests for UserProfile model and key views"
Enter fullscreen mode Exit fullscreen mode

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)