Middleware and Signals
Intercepting requests globally and decoupling app logic using event listeners.
🧑🏫 Sabse pehle — simple mein samjho#
Node.js mein hum middleware banate the har request ko check karne ke liye. Django mein bhi Middleware wahi kaam karta hai — request View tak pahunchne se pehle aur response wapas jaane se pehle. Dusra important concept hai Signals. Ye events (Event Emitter) ki tarah hote hain. Socho agar tumhe rules likhne hain ki jab bhi naya User banay, toh apne aap ek UserProfile create ho jaye. Is logic ko View mein likhne ke bajaye, tum ek Signal bana dete ho jo background mein listen karta rehta hai aur jaise hi User save hota hai, wo Profile bana deta hai.
1. Django Middleware#
Middleware in Django is a class with a specific structure. It hooks into the request/response lifecycle globally.
Creating Custom Middleware#
Create a file named middleware.py in your app.
import time
class TimingMiddleware:
# 1. Initialization (Runs once when the server starts)
def __init__(self, get_response):
self.get_response = get_response
# 2. The Execution (Runs on every request)
def __call__(self, request):
# --- Code executed BEFORE the view runs ---
start_time = time.time()
# The view (or the next middleware) is called here
response = self.get_response(request)
# --- Code executed AFTER the view finishes ---
duration = time.time() - start_time
# Add a custom header to the response
response['X-Process-Time'] = str(duration)
return response
Registering Middleware#
You must add the exact path of your middleware class to the MIDDLEWARE list in settings.py. Order matters drastically! Django executes them top-to-bottom for incoming requests, and bottom-to-top for outgoing responses.
# settings.py
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
# ... other standard middleware ...
'blog.middleware.TimingMiddleware', # Your custom middleware
]
2. Django Signals#
Signals allow decoupled applications to get notified when actions occur elsewhere in the framework. It's the Observer pattern (like Node's EventEmitter).
The most commonly used built-in signals are:
post_save: Fired immediately after an object is saved to the database.pre_save: Fired just before an object is saved.post_delete: Fired after an object is deleted.
Example: Auto-creating a Profile when a User registers#
Create a file named signals.py in your app.
from django.db.models.signals import post_save
from django.dispatch import receiver
from django.contrib.auth.models import User
from .models import Profile
# The @receiver decorator tells Django to listen for the post_save event specifically from the User model
@receiver(post_save, sender=User)
def create_user_profile(sender, instance, created, **kwargs):
# 'instance' is the actual User object that was just saved in the database
# 'created' is a boolean: True if it's a brand new user, False if an existing user was just updated
if created:
# Create a matching Profile for this new user
Profile.objects.create(user=instance)
@receiver(post_save, sender=User)
def save_user_profile(sender, instance, **kwargs):
# If the user is updated, ensure their profile is saved too
instance.profile.save()
Registering Signals#
For signals to work, Django needs to know they exist when the app starts up. You must import them in your app's apps.py file.
blog/apps.py
from django.apps import AppConfig
class BlogConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'blog'
def ready(self):
# Import the signals file when the app initializes
import blog.signals
Signals are incredibly powerful for keeping your Views clean and decoupled!