Session Overview

  • Context Processor
  • Professional Navigation Bar
  • User Registration
  • Login & Logout
  • User Profile
  • Automatically Create User Profile

Refactor Using a Context Processor

Until now, we passed the categories list manually from every View.

As the project grows, repeating the same code in multiple Views makes maintenance difficult. Django provides Context Processors to share common data across all Templates.

Current Approach
def home(request):

    posts = Post.objects.filter(
        IsPublished=True
    )

    categories = Category.objects.all()

    return render(
        request,
        'home.html',
        {
            'posts': posts,
            'categories': categories
        }
    )
Problem

Every new View (Home, Blog Details, Login, Register, Profile, etc.) would need the same categories code.

Step 1 - Create context_processors.py
blog/context_processors.py
Step 2 - Add the Following Code
from .models import Category


def category_menu(request):

    return {

        'categories': Category.objects.all()

    }
Result The categories variable is now available in every Template without passing it manually from each View.

User Registration using Django Authentication

Django provides a built-in UserCreationForm that allows users to register securely without writing custom validation code.

It automatically validates user input and stores passwords in encrypted form.

Step 1 - Update views.py
from django.contrib.auth.forms import UserCreationForm
from django.shortcuts import render, redirect


def register(request):

    if request.method == "POST":

        form = UserCreationForm(request.POST)

        if form.is_valid():

            form.save()

            return redirect("login")

    else:

        form = UserCreationForm()

    return render(
        request,
        "register.html",
        {
            "form": form
        }
    )
Step 2 - Update blog/urls.py
path(
    "register/",
    views.register,
    name="register"
),
Step 3 - Create register.html
{% extends 'base.html' %}

{% block content %}

<div class="container mt-5">

    <div class="row justify-content-center">

        <div class="col-md-5">

            <div class="card shadow">

                <div class="card-header">

                    <h3>User Registration</h3>

                </div>

                <div class="card-body">

                    <form method="POST">

                        {% csrf_token %}

                        {{ form.as_p }}

                        <button class="btn btn-primary">

                            Register

                        </button>

                    </form>

                </div>

            </div>

        </div>

    </div>

</div>

{% endblock %}
Result A new user account is created successfully and the user is redirected to the Login page.
Advantages of Using Django's Default User Registration
  • Secure password hashing.
  • Password confirmation is handled automatically.
  • Checks for duplicate usernames.
  • Built-in validation for user credentials.
  • Easy integration with Django Authentication.
  • Follows Django security best practices.

User Login

Django provides a built-in AuthenticationForm for securely authenticating registered users.

Step 1 - Update views.py
from django.contrib.auth.forms import AuthenticationForm
from django.contrib.auth import login


def userLogin(request):

    if request.method == "POST":

        form = AuthenticationForm(
            request,
            data=request.POST
        )

        if form.is_valid():

            login(request, form.get_user())

            return redirect("home")

    else:

        form = AuthenticationForm()

    return render(
        request,
        "login.html",
        {
            "form": form
        }
    )
Step 2 - Update blog/urls.py
path(
    "login/",
    views.userLogin,
    name="login"
),
Step 3 - Create login.html
{% extends 'base.html' %}

{% block content %}

<div class="container mt-5">

    <div class="row justify-content-center">

        <div class="col-md-5">

            <div class="card shadow">

                <div class="card-header">

                    <h3>User Login</h3>

                </div>

                <div class="card-body">

                    <form method="POST">

                        {% csrf_token %}

                        {{ form.as_p }}

                        <button class="btn btn-success">

                            Login

                        </button>

                    </form>

                </div>

            </div>

        </div>

    </div>

</div>

{% endblock %}
Result Registered users can log in securely and are redirected to the Home page after successful authentication.
Advantages of Using Django's Default Login
  • Secure user authentication.
  • Automatically verifies hashed passwords.
  • Creates and manages user sessions.
  • Protects against common authentication mistakes.
  • Easy integration with @login_required.
  • Recommended for most Django applications.

User Logout

Django provides a built-in logout() function to securely end a user's session.

After logging out, the user is redirected to the Home page.

Step 1 - Update views.py
from django.contrib.auth import logout


def userLogout(request):

    logout(request)

    return redirect("home")
Step 2 - Update blog/urls.py
path(
    "logout/",
    views.userLogout,
    name="logout"
),
Step 3 - Update Navigation Bar
{% if user.is_authenticated %}

<li class="nav-item dropdown">

    <a class="nav-link dropdown-toggle"
       href="#"
       role="button"
       data-bs-toggle="dropdown">

        <i class="fa-solid fa-user"></i>

        {{ user.username }}

    </a>

    <ul class="dropdown-menu">

        <li>

            <a class="dropdown-item"
               href="#">

                My Profile

            </a>

        </li>

        <li>

            <a class="dropdown-item"
               href="{% url 'logout' %}">

                Logout

            </a>

        </li>

    </ul>

</li>

{% else %}

<li class="nav-item">

    <a class="nav-link"
       href="{% url 'login' %}">

        Login

    </a>

</li>

<li class="nav-item">

    <a class="nav-link"
       href="{% url 'register' %}">

        Register

    </a>

</li>

{% endif %}
Result After clicking Logout, the user's session is terminated and they are redirected to the Home page.
Why do we use logout()?

The logout() function removes the authenticated user's session from the server.

After logout, the user must log in again to access protected pages.

Create User Profile Model

Django's built-in User model stores only basic authentication information such as Username, Password and Email.

To store additional information like Profile Photo, Mobile Number and Bio, we create a separate UserProfile model.

Step 1 - Update models.py
from django.contrib.auth.models import User


class UserProfile(models.Model):

    User = models.OneToOneField(
        User,
        on_delete=models.CASCADE
    )

    ProfilePhoto = models.ImageField(
        upload_to="profiles/",
        blank=True,
        null=True
    )

    Mobile = models.CharField(
        max_length=15,
        blank=True
    )

    Bio = models.TextField(
        blank=True
    )

    def __str__(self):

        return self.User.username

    class Meta:

        db_table = "UserProfiles"
Step 2 - Create Migration
python manage.py makemigrations

python manage.py migrate
Relationship
User

Username

Password

Email

      │

      │ One-to-One

      ▼

UserProfile

Profile Photo

Mobile

Bio
Why do we create a UserProfile model?
  • The built-in User model should not be modified directly.
  • A OneToOneField extends the User model with additional information.
  • This approach follows Django's recommended practice.
  • Authentication remains separate from application-specific profile data.

Automatically Create User Profile

When a new user registers, we want to automatically create a corresponding UserProfile record.

Django provides a feature called Signals that allows us to execute code automatically when specific events occur.

Step 1 - Create signals.py
blog/signals.py
Step 2 - Add the Following Code
from django.db.models.signals import post_save

from django.dispatch import receiver

from django.contrib.auth.models import User

from .models import UserProfile


@receiver(post_save, sender=User)

def create_user_profile(sender, instance, created, **kwargs):

    if created:

        UserProfile.objects.create(

            User=instance

        )
Step 3 - Load Signals

Open apps.py.

from django.apps import AppConfig


class BlogConfig(AppConfig):

    default_auto_field = 'django.db.models.BigAutoField'

    name = 'blog'

    def ready(self):

        import blog.signals
Result Whenever a new User registers, Django automatically creates an empty UserProfile record.
Understanding apps.py

The ready() method is executed automatically when the Django application starts.

The following line loads the signals.py file so that Django can register and execute our Signals.

import blog.signals

If this line is omitted, the Signal will not be loaded and the UserProfile will not be created automatically after user registration.

The default_auto_field setting specifies the default type of primary key (BigAutoField) for new Models. It is generated automatically by Django and does not affect the Signal implementation.

Understanding Django Signals

A Signal allows Django to automatically execute code when a specific event occurs.

User Registration

        │

        ▼

User Saved

        │

        ▼

post_save Signal

        │

        ▼

Create UserProfile

This keeps our Registration View clean because we do not need to manually create the UserProfile after saving the User.

Quick Revision

Context Processor
  • Shared Template Data
  • Clean Views
  • Reusable Code
Navigation Bar
  • Dynamic Categories
  • Authentication Menu
  • User Dropdown
Registration
  • UserCreationForm
  • Password Hashing
  • Validation
Login & Logout
  • AuthenticationForm
  • login()
  • logout()
User Profile
  • OneToOneField
  • UserProfile Model
  • Additional User Information
Django Signals
  • post_save
  • ready()
  • Automatic Profile Creation
Concepts Learned Today
✓ Context Processor

✓ Dynamic Navigation Bar

✓ User Registration

✓ User Login & Logout

✓ UserProfile Model

✓ OneToOne Relationship

✓ Django Signals

✓ Automatic UserProfile Creation

Assignment

Continue Developing the News Portal

Implement the Authentication module covered in today's Blog Project using your News Portal.

  1. Refactor the project using a Context Processor to display News Categories in every template.
  2. Update the Navigation Bar to display:
    • Dynamic News Categories
    • Login
    • Register
    • User Menu after Login
  3. Create a User Registration page using UserCreationForm.
  4. Create a Login page using AuthenticationForm.
  5. Implement the Logout functionality using Django's built-in logout() function.
  6. Create a UserProfile model using a OneToOneField with Django's User model.
  7. Use a Django Signal to automatically create a UserProfile whenever a new user registers.
  8. Test the complete Authentication flow:
    • Register New User
    • Login
    • Logout
    • Verify that a UserProfile record is created automatically.