Django Middleware Avanzato nel 2026: Middleware Personalizzato, Logging e Domande da Colloquio
Guida completa al Django Middleware nel 2026: ciclo request-response, classi middleware personalizzate, middleware asincrono, integrazione logging e domande tecniche frequenti nei colloqui.

Il middleware Django rappresenta il cuore di ogni ciclo request-response, eppure molti sviluppatori lo trattano come una scatola nera. Comprendere come viene eseguito il middleware, quando scrivere middleware personalizzato e come implementare il logging a livello di middleware distingue gli sviluppatori Django senior dai junior nei colloqui tecnici.
Django 6.0 supporta completamente il middleware asincrono con sintassi async/await nativa. Impostando async_capable = True e sync_capable = False sulla classe middleware, le richieste vengono gestite senza overhead dei thread.
Come Funziona il Ciclo Request-Response nel Middleware Django
Il middleware in Django segue un modello "a cipolla". Quando arriva una richiesta, passa attraverso ogni middleware nella lista MIDDLEWARE dall'alto verso il basso. Quando la view restituisce una risposta, questa attraversa il middleware dal basso verso l'alto. Questo ordinamento è fondamentale: il middleware che necessita di dati di sessione deve essere eseguito dopo SessionMiddleware.
La configurazione MIDDLEWARE predefinita in Django 6.0:
# settings.py
MIDDLEWARE = [
"django.middleware.security.SecurityMiddleware",
"django.contrib.sessions.middleware.SessionMiddleware",
"django.middleware.common.CommonMiddleware",
"django.middleware.csrf.CsrfViewMiddleware",
"django.contrib.auth.middleware.AuthenticationMiddleware",
"django.contrib.messages.middleware.MessageMiddleware",
"django.middleware.clickjacking.XFrameOptionsMiddleware",
]Ogni middleware può interrompere la catena restituendo direttamente una HttpResponse invece di chiamare get_response(). Quando questo accade, il middleware interno e la view non vengono eseguiti, ma il middleware esterno continua a processare la risposta.
Scrivere Middleware Personalizzato Basato su Classi in Django 6.0
Il pattern middleware moderno richiede una classe con metodi __init__ e __call__. Il metodo __init__ viene eseguito una volta all'avvio del server, mentre __call__ viene eseguito per ogni richiesta.
# middleware/timing.py
import time
import logging
logger = logging.getLogger(__name__)
class RequestTimingMiddleware:
"""Registra il tempo impiegato per elaborare ogni richiesta."""
def __init__(self, get_response):
# Chiamato una volta all'avvio del server
self.get_response = get_response
def __call__(self, request):
# Codice prima dell'esecuzione della view
start_time = time.perf_counter()
# Chiama il middleware successivo o la view
response = self.get_response(request)
# Codice dopo l'esecuzione della view
duration_ms = (time.perf_counter() - start_time) * 1000
logger.info(
"Request %s %s completata in %.2fms",
request.method,
request.path,
duration_ms
)
return responseIl middleware viene registrato in settings.py aggiungendo il suo percorso di importazione a MIDDLEWARE. La posizione è importante: il middleware di timing dovrebbe essere posizionato all'inizio della lista per misurare l'intero ciclo di vita della richiesta.
Middleware Asincrono per Applicazioni Django ad Alta Concorrenza
Django 6.0 gestisce le richieste asincrone nativamente. Per le applicazioni che girano sotto ASGI con view asincrone, il middleware sincrono crea colli di bottiglia nelle performance perché Django avvolge il middleware sincrono in executor di thread pool. Scrivere middleware asincrono elimina questo overhead.
# middleware/async_timing.py
import time
import logging
from asgiref.sync import iscoroutinefunction, markcoroutinefunction
logger = logging.getLogger(__name__)
class AsyncRequestTimingMiddleware:
"""Middleware di timing async-native per deployment ASGI."""
async_capable = True
sync_capable = False
def __init__(self, get_response):
self.get_response = get_response
if iscoroutinefunction(self.get_response):
markcoroutinefunction(self)
async def __call__(self, request):
start_time = time.perf_counter()
# Attende il middleware successivo o la view asincrona
response = await self.get_response(request)
duration_ms = (time.perf_counter() - start_time) * 1000
logger.info(
"Async request %s %s completata in %.2fms",
request.method,
request.path,
duration_ms
)
return responseIl decorator @sync_and_async_middleware da django.utils.decorators crea middleware che gestisce sia richieste sincrone che asincrone verificando iscoroutinefunction(get_response) a runtime.
Implementare Middleware per il Logging con Request ID
Correlare i log in sistemi distribuiti richiede un identificatore univoco per ogni richiesta. Questo pattern appare frequentemente nelle domande di colloquio Django perché dimostra la comprensione di middleware, logging e debugging di sistemi in produzione.
# middleware/request_id.py
import uuid
import logging
class RequestIDMiddleware:
"""Associa un ID univoco a ogni richiesta per la correlazione dei log."""
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
# Genera o estrae l'ID della richiesta dall'header
request_id = request.headers.get("X-Request-ID")
if not request_id:
request_id = str(uuid.uuid4())
# Associa all'oggetto request per l'accesso nelle view
request.request_id = request_id
response = self.get_response(request)
# Aggiunge l'ID della richiesta agli header della risposta
response["X-Request-ID"] = request_id
return responsePer includere request_id in tutti i messaggi di log, viene creato un filtro di logging personalizzato:
# logging_filters.py
import logging
class RequestIDFilter(logging.Filter):
"""Inietta request_id nei record di log."""
def filter(self, record):
from django.middleware.request_id import local
record.request_id = getattr(local, "request_id", "no-request-id")
return TrueIl filtro viene configurato in settings.py:
# settings.py
LOGGING = {
"version": 1,
"disable_existing_loggers": False,
"filters": {
"request_id": {
"()": "logging_filters.RequestIDFilter",
},
},
"formatters": {
"verbose": {
"format": "[{levelname}] {asctime} [{request_id}] {name}: {message}",
"style": "{",
},
},
"handlers": {
"console": {
"class": "logging.StreamHandler",
"formatter": "verbose",
"filters": ["request_id"],
},
},
"root": {
"handlers": ["console"],
"level": "INFO",
},
}Pronto a superare i tuoi colloqui su Django?
Pratica con i nostri simulatori interattivi, flashcards e test tecnici.
Metodi Hook del Middleware per un Controllo Granulare
Oltre a __call__, il middleware Django supporta tre metodi hook: process_view, process_exception e process_template_response. Questi forniscono controllo in punti specifici del ciclo di vita della richiesta.
process_view per la Logica Pre-Esecuzione
# middleware/permission_check.py
from django.http import HttpResponseForbidden
class PermissionCheckMiddleware:
"""Verifica i permessi prima dell'esecuzione della view."""
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
return self.get_response(request)
def process_view(self, request, view_func, view_args, view_kwargs):
# Accede ai metadati della view
required_permission = getattr(view_func, "required_permission", None)
if required_permission:
if not request.user.has_perm(required_permission):
return HttpResponseForbidden("Permesso negato")
# Restituisce None per continuare alla view
return NoneQuesto pattern permette di decorare le view con requisiti di permesso:
# views.py
def require_permission(perm):
def decorator(view_func):
view_func.required_permission = perm
return view_func
return decorator
@require_permission("app.can_edit")
def edit_resource(request, pk):
# Logica della view
passprocess_exception per la Gestione Centralizzata degli Errori
# middleware/error_tracking.py
import logging
import traceback
logger = logging.getLogger(__name__)
class ErrorTrackingMiddleware:
"""Registra le eccezioni con contesto completo prima che Django le gestisca."""
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
return self.get_response(request)
def process_exception(self, request, exception):
logger.error(
"Eccezione non gestita in %s %s: %s\n%s",
request.method,
request.path,
str(exception),
traceback.format_exc(),
extra={
"user_id": getattr(request.user, "id", None),
"request_id": getattr(request, "request_id", None),
}
)
# Restituisce None per lasciare che Django gestisca l'eccezione
return NoneI metodi process_exception del middleware vengono eseguiti in ordine inverso. Se uno restituisce una HttpResponse, il middleware precedente nella lista non vedrà l'eccezione.
Aggiornamenti del Middleware di Sicurezza in Django 6.0
Django 6.0 include diverse correzioni di sicurezza per UpdateCacheMiddleware. Secondo le release di sicurezza Django del 2026, le risposte con Cache-Control: private in maiuscole/minuscole miste venivano memorizzate nella cache in modo errato, e le risposte alle richieste con header Authorization potevano essere archiviate in cache condivise.
Il LoginRequiredMiddleware, introdotto in Django 5.1, impone l'autenticazione a livello di sito:
# settings.py
MIDDLEWARE = [
# ... altro middleware
"django.contrib.auth.middleware.LoginRequiredMiddleware",
]
# Esentare view specifiche
from django.contrib.auth.decorators import login_not_required
@login_not_required
def public_view(request):
return HttpResponse("Contenuto pubblico")Questo inverte il pattern tradizionale di decorare le view protette con @login_required. Per le applicazioni dove la maggior parte delle view richiede autenticazione, questo riduce il codice boilerplate e previene l'esposizione accidentale di endpoint protetti.
MiddlewareMixin e Migrazione dal Middleware Legacy
Il MiddlewareMixin fa da ponte tra il middleware vecchio stile (che usa i metodi process_request e process_response) e il nuovo pattern callable. Nota: django.utils.deprecation.MiddlewareMixin è deprecato e verrà rimosso in Django 6.2. Usare invece django.middleware.MiddlewareMixin.
# middleware/legacy_style.py
from django.middleware import MiddlewareMixin
class LegacyStyleMiddleware(MiddlewareMixin):
"""Middleware che usa il pattern legacy basato su hook."""
def process_request(self, request):
# Chiamato prima della view, restituisce None per continuare
request.custom_attribute = "value"
return None
def process_response(self, request, response):
# Chiamato dopo la view, deve restituire la response
response["X-Custom-Header"] = "middleware-added"
return responsePer il nuovo middleware, evitare MiddlewareMixin. Il pattern callable fornisce un flusso di controllo più chiaro e migliore compatibilità con Django asincrono.
Domande Frequenti sul Middleware Django nei Colloqui
I colloqui tecnici spesso includono domande sul middleware per valutare la comprensione del ciclo di vita delle richieste in Django. Queste domande appaiono frequentemente nei colloqui per sviluppatori Django senior.
D: Qual è la differenza tra l'ordinamento del middleware e l'ordine di esecuzione per le risposte?
Il middleware elabora le richieste dall'alto verso il basso attraverso MIDDLEWARE, ma elabora le risposte dal basso verso l'alto. Si può pensare come a una cipolla: il middleware più esterno è il primo a vedere la richiesta e l'ultimo a vedere la risposta.
D: Come funziona l'interruzione della catena del middleware?
Quando il middleware restituisce una HttpResponse invece di chiamare get_response(), la richiesta non raggiunge mai il middleware interno o la view. La risposta passa comunque attraverso tutto il middleware esterno nel suo percorso di ritorno. Questo comportamento differisce dalla vecchia impostazione MIDDLEWARE_CLASSES, dove tutti i metodi process_response venivano eseguiti indipendentemente dall'interruzione.
D: Quando il middleware dovrebbe accedere a request.user?
Solo dopo che AuthenticationMiddleware è stato eseguito. Accedere a request.user prima che il middleware di autenticazione lo associ solleva un AttributeError. Il middleware personalizzato che necessita di informazioni sull'utente dovrebbe essere posizionato dopo AuthenticationMiddleware nella lista MIDDLEWARE.
D: Come si rende il middleware compatibile con l'asincrono?
Impostare async_capable = True sulla classe middleware e implementare __call__ come metodo asincrono usando await get_response(request). Per middleware che deve funzionare sia in contesti sincroni che asincroni, usare @sync_and_async_middleware e verificare iscoroutinefunction(get_response) per ramificare di conseguenza.
Inizia a praticare!
Metti alla prova le tue conoscenze con i nostri simulatori di colloquio e test tecnici.
Padroneggiare il Middleware Django per Produzione e Colloqui
Il middleware Django controlla le preoccupazioni trasversali che attraversano l'intero ciclo di vita della richiesta. I punti chiave per lavorare con il middleware in Django 6.0:
- Il middleware viene eseguito secondo un pattern a cipolla: la richiesta fluisce dall'alto verso il basso, la risposta dal basso verso l'alto
- Impostare
async_capable = Trueper middleware async-native nei deployment ASGI per evitare l'overhead del thread pool - Usare
process_viewper ispezionare i metadati della view prima dell'esecuzione,process_exceptionper il logging centralizzato degli errori - Il middleware Request ID abilita la correlazione dei log attraverso servizi distribuiti, un requisito comune in produzione
LoginRequiredMiddlewareinverte il pattern di autenticazione: le view sono protette di default, le view pubbliche sono esplicitamente esentate- Il deprecato
django.utils.deprecation.MiddlewareMixinpassa adjango.middleware.MiddlewareMixinin Django 6.2 - L'ordinamento del middleware determina quali componenti vedono
request.user, i dati di sessione e altri attributi della richiesta
Per una copertura più approfondita dei pattern Django ORM e REST Framework, consultare la guida all'ottimizzazione Django ORM.
Sapresti trovare il bug in Django?
Uno snippet reale, un bug nascosto, un tentativo al giorno. Senza account per provare.

Scritto da
Anthony Fillion-MailletFondatore di SharpSkill
Sviluppatore fullstack da oltre 10 anni. Guida SharpSkill e risponde di tutto ciò che vi viene pubblicato.
Aggiornato il 18 settembre 2026
Tag
Condividi
Articoli correlati

Django 5.2: Custom Middleware e Gestione dei Segnali per Colloqui Tecnici
Padroneggiare middleware e segnali in Django 5.2: pipeline middleware, middleware asincrono, pre_save/post_save signals e pattern comuni nei colloqui tecnici.

Domande Colloquio Django: ORM, Middleware e DRF in Profondità
Domande colloquio Django su ottimizzazione ORM con FETCH_PEERS, architettura middleware e performance serializer DRF. Esempi di codice con Django 6.1.

Django e Celery: Elaborazione Asincrona dei Task e Domande da Colloquio 2026
Guida completa a Django e Celery: configurazione, task asincroni, code, Celery Beat, monitoraggio e domande frequenti nei colloqui tecnici 2026.