Skip to main content

Django: User Registration and Login

Django: User Registration and Login

User registration and login are essential features for web applications, enabling secure user management and personalized experiences. Built on Django’s robust Model-View-Template (MVT) architecture and leveraging the django.contrib.auth package, Django simplifies these processes with built-in authentication tools and customizable forms. This tutorial explores Django user registration and login, covering setup, customization, and practical applications for secure user authentication.


01. Why Implement User Registration and Login?

User registration allows new users to create accounts, while login authenticates existing users, granting access to protected resources. Django’s authentication system provides secure password hashing, session management, and built-in views, making it ideal for applications like blogs, e-commerce platforms, or dashboards. Customizing these features ensures a tailored user experience while maintaining security.

Example: Basic Authentication Setup

# myproject/settings.py
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'myapp',
]
LOGIN_REDIRECT_URL = 'dashboard'
LOGOUT_REDIRECT_URL = 'login'

# myproject/urls.py
from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('accounts/', include('django.contrib.auth.urls')),
    path('', include('myapp.urls')),
]

Output:

Login page accessible at http://127.0.0.1:8000/accounts/login/.

Explanation:

  • django.contrib.auth - Enables authentication features.
  • LOGIN_REDIRECT_URL - Directs users after login.

02. Key Concepts for Registration and Login

Django’s authentication system provides tools to streamline user registration and login. The table below summarizes key components and their roles:

Component Description Use Case
User Model Stores user data like username, email, password Create and authenticate users
Authentication Views Built-in views for login, logout Handle user sessions
Forms Custom forms for registration and login Validate user input
Decorators Restrict access to authenticated users Protect views


2.1 Setting Up User Login

Example: Custom Login View and Template

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

def custom_login(request):
    if request.method == 'POST':
        username = request.POST['username']
        password = request.POST['password']
        user = authenticate(request, username=username, password=password)
        if user is not None:
            login(request, user)
            return redirect('dashboard')
        else:
            return render(request, 'myapp/login.html', {'error': 'Invalid credentials'})
    return render(request, 'myapp/login.html')

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

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

# myapp/templates/myapp/login.html
{% extends "base.html" %}
{% block content %}
    <h2>Login</h2>
    {% if error %}
        <p style="color: red;">{{ error }}</p>
    {% endif %}
    <form method="post">
        {% csrf_token %}
        <label>Username: <input type="text" name="username"></label><br>
        <label>Password: <input type="password" name="password"></label><br>
        <button type="submit">Login</button>
    </form>
{% endblock %}

Output:

Custom login page at http://127.0.0.1:8000/login/ with error handling.

Explanation:

  • authenticate - Verifies user credentials.
  • login - Starts a user session.

2.2 Implementing User Registration

Example: Registration Form and View

# myapp/forms.py
from django import forms
from django.contrib.auth.models import User

class RegisterForm(forms.ModelForm):
    password = forms.CharField(widget=forms.PasswordInput)
    password_confirm = forms.CharField(widget=forms.PasswordInput)

    class Meta:
        model = User
        fields = ['username', 'email', 'password']

    def clean(self):
        cleaned_data = super().clean()
        password = cleaned_data.get('password')
        password_confirm = cleaned_data.get('password_confirm')
        if password and password_confirm and password != password_confirm:
            raise forms.ValidationError("Passwords do not match.")
        return cleaned_data

# myapp/views.py
from django.shortcuts import render, redirect
from .forms import RegisterForm

def register(request):
    if request.method == 'POST':
        form = RegisterForm(request.POST)
        if form.is_valid():
            user = form.save(commit=False)
            user.set_password(form.cleaned_data['password'])
            user.save()
            return redirect('login')
    else:
        form = RegisterForm()
    return render(request, 'myapp/register.html', {'form': form})

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

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

# myapp/templates/myapp/register.html
{% extends "base.html" %}
{% block content %}
    <h2>Register</h2>
    <form method="post">
        {% csrf_token %}
        {{ form.as_p }}
        <button type="submit">Register</button>
    </form>
{% endblock %}

Output:

Registration form at http://127.0.0.1:8000/register/ creates new users.

Explanation:

  • set_password - Securely hashes the password.
  • clean - Validates password confirmation.

2.3 Protecting Views with Authentication

Example: Restricted Dashboard

# myapp/views.py
from django.contrib.auth.decorators import login_required
from django.shortcuts import render

@login_required
def dashboard(request):
    return render(request, 'myapp/dashboard.html', {'user': request.user})

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

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

# myapp/templates/myapp/dashboard.html
{% extends "base.html" %}
{% block content %}
    <h2>Welcome, {{ user.username }}!</h2>
    <p>Email: {{ user.email }}</p>
    <a href="{% url 'logout' %}">Logout</a>
{% endblock %}

Output:

Dashboard at http://127.0.0.1:8000/dashboard/ requires login.

Explanation:

  • login_required - Restricts access to authenticated users.
  • Redirects unauthenticated users to the login page.

2.4 Using Built-in Logout

Example: Logout Functionality

# myproject/urls.py
from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('accounts/', include('django.contrib.auth.urls')),
    path('', include('myapp.urls')),
]

# myapp/templates/base.html
<!DOCTYPE html>
<html>
<head>
    <title>My App</title>
</head>
<body>
    {% if user.is_authenticated %}
        <p>Welcome, {{ user.username }} | <a href="{% url 'logout' %}">Logout</a></p>
    {% else %}
        <p><a href="{% url 'login' %}">Login</a> | <a href="{% url 'register' %}">Register</a></p>
    {% endif %}
    {% block content %}
    {% endblock %}
</body>
</html>

Output:

Logout link redirects to http://127.0.0.1:8000/accounts/login/ after ending session.

Explanation:

  • django.contrib.auth.urls - Includes logout/ URL.
  • Base template provides navigation based on authentication status.

2.5 Incorrect Authentication Setup

Example: Insecure Registration

# myapp/views.py (Incorrect)
from django.contrib.auth.models import User
from django.shortcuts import redirect

def register(request):
    username = request.POST['username']
    password = request.POST['password']  # Incorrect: Plain text
    User.objects.create(username=username, password=password)
    return redirect('login')

Output:

Passwords stored unhashed, vulnerable to breaches.

Explanation:

  • Storing plain-text passwords compromises security.
  • Solution: Use set_password for secure hashing.

03. Effective Usage

3.1 Recommended Practices

  • Combine built-in authentication views with custom forms for secure, user-friendly registration and login.

Example: Comprehensive Registration and Login

# myproject/settings.py
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'myapp',
]
LOGIN_REDIRECT_URL = 'dashboard'
LOGOUT_REDIRECT_URL = 'login'
AUTH_PASSWORD_VALIDATORS = [
    {'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', 'OPTIONS': {'min_length': 8}},
    {'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator'},
]

# myapp/forms.py
from django import forms
from django.contrib.auth.models import User

class RegisterForm(forms.ModelForm):
    password = forms.CharField(widget=forms.PasswordInput)
    password_confirm = forms.CharField(widget=forms.PasswordInput)

    class Meta:
        model = User
        fields = ['username', 'email', 'password']

    def clean(self):
        cleaned_data = super().clean()
        password = cleaned_data.get('password')
        password_confirm = cleaned_data.get('password_confirm')
        if password and password_confirm and password != password_confirm:
            raise forms.ValidationError("Passwords do not match.")
        return cleaned_data

# myapp/views.py
from django.contrib.auth import authenticate, login
from django.contrib.auth.decorators import login_required
from django.shortcuts import render, redirect
from .forms import RegisterForm

def custom_login(request):
    if request.method == 'POST':
        username = request.POST['username']
        password = request.POST['password']
        user = authenticate(request, username=username, password=password)
        if user is not None:
            login(request, user)
            return redirect('dashboard')
        else:
            return render(request, 'myapp/login.html', {'error': 'Invalid credentials'})
    return render(request, 'myapp/login.html')

def register(request):
    if request.method == 'POST':
        form = RegisterForm(request.POST)
        if form.is_valid():
            user = form.save(commit=False)
            user.set_password(form.cleaned_data['password'])
            user.save()
            return redirect('login')
    else:
        form = RegisterForm()
    return render(request, 'myapp/register.html', {'form': form})

@login_required
def dashboard(request):
    return render(request, 'myapp/dashboard.html', {'user': request.user})

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

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

# myapp/templates/myapp/login.html
{% extends "base.html" %}
{% block content %}
    <h2>Login</h2>
    {% if error %}
        <p style="color: red;">{{ error }}</p>
    {% endif %}
    <form method="post">
        {% csrf_token %}
        <label>Username: <input type="text" name="username"></label><br>
        <label>Password: <input type="password" name="password"></label><br>
        <button type="submit">Login</button>
    </form>
    <p>Don't have an account? <a href="{% url 'register' %}">Register</a></p>
{% endblock %}

# myapp/templates/myapp/register.html
{% extends "base.html" %}
{% block content %}
    <h2>Register</h2>
    <form method="post">
        {% csrf_token %}
        {{ form.as_p }}
        <button type="submit">Register</button>
    </form>
    <p>Already have an account? <a href="{% url 'login' %}">Login</a></p>
{% endblock %}

Output:

Secure registration and login with protected dashboard at http://127.0.0.1:8000/dashboard/.
  • Custom forms validate user input securely.
  • Password validators enforce strong passwords.
  • Decorators protect sensitive views.

3.2 Practices to Avoid

  • Avoid skipping validation or using insecure password storage.

Example: Unvalidated Registration

# myapp/views.py (Incorrect)
from django.contrib.auth.models import User
from django.shortcuts import redirect

def register(request):
    User.objects.create(username=request.POST['username'], password=request.POST['password'])
    return redirect('login')

Output:

Unvalidated input and plain-text passwords create security risks.
  • Lack of validation risks invalid data or attacks.
  • Solution: Use forms with set_password and validation.

04. Common Use Cases

4.1 User Authentication for Blogs

Enable users to register and log in to access or create blog content.

Example: Blog User Access

# myapp/views.py
from django.contrib.auth.decorators import login_required
from django.shortcuts import render
from .models import Post

@login_required
def blog(request):
    posts = Post.objects.filter(author=request.user)
    return render(request, 'myapp/blog.html', {'posts': posts})

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

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

Output:

Users access their posts at http://127.0.0.1:8000/blog/ after login.

Explanation:

  • login_required - Restricts blog access to authenticated users.
  • Filters posts by user for personalized content.

4.2 Secure Profile Management

Allow users to register and update their profiles securely.

Example: Profile Update

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

class Profile(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    bio = models.TextField(blank=True)

# myapp/forms.py
from django import forms
from .models import Profile

class ProfileForm(forms.ModelForm):
    class Meta:
        model = Profile
        fields = ['bio']

# myapp/views.py
from django.contrib.auth.decorators import login_required
from django.shortcuts import render, redirect
from .forms import ProfileForm

@login_required
def update_profile(request):
    profile, created = Profile.objects.get_or_create(user=request.user)
    if request.method == 'POST':
        form = ProfileForm(request.POST, instance=profile)
        if form.is_valid():
            form.save()
            return redirect('dashboard')
    else:
        form = ProfileForm(instance=profile)
    return render(request, 'myapp/update_profile.html', {'form': form})

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

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

# myapp/templates/myapp/update_profile.html
{% extends "base.html" %}
{% block content %}
    <h2>Update Profile</h2>
    <form method="post">
        {% csrf_token %}
        {{ form.as_p }}
        <button type="submit">Save</button>
    </form>
{% endblock %}

Output:

Users update profiles at http://127.0.0.1:8000/profile/ after login.

Explanation:

  • get_or_create - Ensures a profile exists for the user.
  • Secure form saves profile data for authenticated users.

Conclusion

Django’s user registration and login, integrated with the Model-View-Template architecture, provide a secure and efficient framework for user authentication. Key takeaways:

  • Use built-in authentication URLs and custom forms for quick setup.
  • Secure views with login_required and validate input.
  • Implement registration with password hashing and validation.
  • Avoid insecure practices like plain-text passwords or unvalidated input.

With Django’s authentication system, you can build secure, user-friendly registration and login flows for web applications!

Comments