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.
def home(request):
posts = Post.objects.filter(
IsPublished=True
)
categories = Category.objects.all()
return render(
request,
'home.html',
{
'posts': posts,
'categories': categories
}
)
Every new View (Home, Blog Details, Login, Register, Profile, etc.) would need the same categories code.
blog/context_processors.py
from .models import Category
def category_menu(request):
return {
'categories': Category.objects.all()
}
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.
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
}
)
path(
"register/",
views.register,
name="register"
),
{% 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 %}
Django provides a built-in AuthenticationForm for securely authenticating registered users.
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
}
)
path(
"login/",
views.userLogin,
name="login"
),
{% 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 %}
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.
from django.contrib.auth import logout
def userLogout(request):
logout(request)
return redirect("home")
path(
"logout/",
views.userLogout,
name="logout"
),
{% 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 %}
The logout() function removes the authenticated user's session from the server.
After logout, the user must log in again to access protected pages.
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.
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"
python manage.py makemigrations
python manage.py migrate
User
Username
Password
Email
│
│ One-to-One
▼
UserProfile
Profile Photo
Mobile
Bio
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.
blog/signals.py
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
)
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
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.
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.
✓ Context Processor
✓ Dynamic Navigation Bar
✓ User Registration
✓ User Login & Logout
✓ UserProfile Model
✓ OneToOne Relationship
✓ Django Signals
✓ Automatic UserProfile Creation
Implement the Authentication module covered in today's Blog Project using your News Portal.