Geavanceerde Django Middleware in 2026: Custom Middleware, Logging en Sollicitatievragen

Uitgebreide gids over Django Middleware in 2026: request-response cyclus, aangepaste middleware-klassen, async middleware, logging-integratie en veelgestelde technische sollicitatievragen.

Geavanceerde Django Middleware in 2026

Django middleware vormt de kern van elke request-response cyclus, maar veel ontwikkelaars behandelen het als een black box. Het begrijpen van hoe middleware wordt uitgevoerd, wanneer custom middleware te schrijven en hoe logging op middleware-niveau te implementeren, onderscheidt senior Django-ontwikkelaars van juniors in technische sollicitaties.

Django 6.0 Middleware

Django 6.0 ondersteunt async middleware volledig met native async/await syntax. Door async_capable = True en sync_capable = False in te stellen op de middleware-klasse worden requests verwerkt zonder thread overhead.

Hoe Django Middleware de Request-Response Cyclus Uitvoert

Middleware in Django volgt een "ui"-model. Wanneer een request binnenkomt, passeert deze elke middleware in de MIDDLEWARE-lijst van boven naar beneden. Wanneer de view een response retourneert, passeert de response de middleware van onder naar boven. Deze volgorde is cruciaal: middleware die sessiegegevens nodig heeft, moet na SessionMiddleware worden uitgevoerd.

De standaard MIDDLEWARE-configuratie in Django 6.0:

python
# 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",
]

Elke middleware kan de keten onderbreken door direct een HttpResponse te retourneren in plaats van get_response() aan te roepen. Wanneer dit gebeurt, worden binnenste middleware en de view niet uitgevoerd, maar buitenste middleware verwerkt de response nog steeds.

Klasse-gebaseerde Custom Middleware Schrijven in Django 6.0

Het moderne middleware-patroon vereist een klasse met __init__- en __call__-methoden. De __init__-methode wordt eenmaal uitgevoerd bij het starten van de server, terwijl __call__ bij elke request wordt uitgevoerd.

python
# middleware/timing.py
import time
import logging

logger = logging.getLogger(__name__)

class RequestTimingMiddleware:
    """Logt de tijd die nodig is om elke request te verwerken."""

    def __init__(self, get_response):
        # Eenmaal aangeroepen bij serverstart
        self.get_response = get_response

    def __call__(self, request):
        # Code voordat de view wordt uitgevoerd
        start_time = time.perf_counter()

        # Roep de volgende middleware of view aan
        response = self.get_response(request)

        # Code nadat de view is uitgevoerd
        duration_ms = (time.perf_counter() - start_time) * 1000
        logger.info(
            "Request %s %s voltooid in %.2fms",
            request.method,
            request.path,
            duration_ms
        )

        return response

De middleware wordt geregistreerd in settings.py door het importpad toe te voegen aan MIDDLEWARE. Positie is belangrijk: plaats timing middleware vroeg in de lijst om de volledige request-levenscyclus te meten.

Async Middleware voor High-Concurrency Django Applicaties

Django 6.0 verwerkt async requests native. Voor applicaties die onder ASGI draaien met async views, creëert sync middleware performance-bottlenecks omdat Django sync middleware in thread pool executors wraps. Het schrijven van async middleware elimineert deze overhead.

python
# middleware/async_timing.py
import time
import logging
from asgiref.sync import iscoroutinefunction, markcoroutinefunction

logger = logging.getLogger(__name__)

class AsyncRequestTimingMiddleware:
    """Async-native timing middleware voor ASGI deployments."""

    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()

        # Await de volgende middleware of async view
        response = await self.get_response(request)

        duration_ms = (time.perf_counter() - start_time) * 1000
        logger.info(
            "Async request %s %s voltooid in %.2fms",
            request.method,
            request.path,
            duration_ms
        )

        return response

De @sync_and_async_middleware decorator uit django.utils.decorators creëert middleware die zowel sync als async requests verwerkt door iscoroutinefunction(get_response) te controleren tijdens runtime.

Request ID Logging Middleware Implementeren

Het correleren van logs in gedistribueerde systemen vereist een unieke identifier per request. Dit patroon verschijnt regelmatig in Django sollicitatievragen omdat het begrip van middleware, logging en debugging van productiesystemen demonstreert.

python
# middleware/request_id.py
import uuid
import logging

class RequestIDMiddleware:
    """Koppelt een uniek request ID aan elke request voor log-correlatie."""

    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):
        # Genereer of extraheer request ID uit header
        request_id = request.headers.get("X-Request-ID")
        if not request_id:
            request_id = str(uuid.uuid4())

        # Koppel aan request object voor toegang in views
        request.request_id = request_id

        response = self.get_response(request)

        # Voeg request ID toe aan response headers
        response["X-Request-ID"] = request_id

        return response

Om request_id in alle logberichten op te nemen, wordt een aangepast logging filter gemaakt:

python
# logging_filters.py
import logging

class RequestIDFilter(logging.Filter):
    """Injecteert request_id in log records."""

    def filter(self, record):
        from django.middleware.request_id import local
        record.request_id = getattr(local, "request_id", "no-request-id")
        return True

Het filter wordt geconfigureerd in settings.py:

python
# 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",
    },
}

Klaar om je Django gesprekken te halen?

Oefen met onze interactieve simulatoren, flashcards en technische tests.

Middleware Hook Methoden voor Fijnmazige Controle

Naast __call__ ondersteunt Django middleware drie hook methoden: process_view, process_exception en process_template_response. Deze bieden controle op specifieke punten in de request-levenscyclus.

process_view voor Pre-Executie Logica

python
# middleware/permission_check.py
from django.http import HttpResponseForbidden

class PermissionCheckMiddleware:
    """Controleert permissies voordat de view wordt uitgevoerd."""

    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):
        # Toegang tot view metadata
        required_permission = getattr(view_func, "required_permission", None)

        if required_permission:
            if not request.user.has_perm(required_permission):
                return HttpResponseForbidden("Toegang geweigerd")

        # Retourneer None om door te gaan naar de view
        return None

Dit patroon maakt het mogelijk om views te decoreren met permissie-vereisten:

python
# 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):
    # View logica
    pass

process_exception voor Gecentraliseerde Foutafhandeling

python
# middleware/error_tracking.py
import logging
import traceback

logger = logging.getLogger(__name__)

class ErrorTrackingMiddleware:
    """Logt exceptions met volledige context voordat Django ze afhandelt."""

    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(
            "Onafgehandelde exception 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),
            }
        )
        # Retourneer None om Django de exception te laten afhandelen
        return None

Middleware process_exception methoden worden in omgekeerde volgorde uitgevoerd. Als een een HttpResponse retourneert, ziet middleware eerder in de lijst de exception niet.

Django 6.0 Security Middleware Updates

Django 6.0 bevatte verschillende security fixes voor UpdateCacheMiddleware. Volgens de Django security releases van 2026 werden responses met Cache-Control: private in gemengde hoofdletters incorrect gecachet, en konden responses op requests met Authorization headers worden opgeslagen in gedeelde caches.

De LoginRequiredMiddleware, geïntroduceerd in Django 5.1, forceert authenticatie site-breed:

python
# settings.py
MIDDLEWARE = [
    # ... andere middleware
    "django.contrib.auth.middleware.LoginRequiredMiddleware",
]

# Specifieke views vrijstellen
from django.contrib.auth.decorators import login_not_required

@login_not_required
def public_view(request):
    return HttpResponse("Publieke content")

Dit inverteert het traditionele patroon van beschermde views decoreren met @login_required. Voor applicaties waar de meeste views authenticatie vereisen, vermindert dit boilerplate en voorkomt het per ongeluk blootstellen van beschermde endpoints.

MiddlewareMixin en Migratie van Legacy Middleware

De MiddlewareMixin overbrugt oude-stijl middleware (met process_request en process_response methoden) naar het nieuwe callable patroon. Let op: django.utils.deprecation.MiddlewareMixin is deprecated en wordt verwijderd in Django 6.2. Gebruik in plaats daarvan django.middleware.MiddlewareMixin.

python
# middleware/legacy_style.py
from django.middleware import MiddlewareMixin

class LegacyStyleMiddleware(MiddlewareMixin):
    """Middleware die het legacy hook-gebaseerde patroon gebruikt."""

    def process_request(self, request):
        # Aangeroepen voor de view, retourneer None om door te gaan
        request.custom_attribute = "value"
        return None

    def process_response(self, request, response):
        # Aangeroepen na de view, moet response retourneren
        response["X-Custom-Header"] = "middleware-added"
        return response

Voor nieuwe middleware wordt aangeraden MiddlewareMixin te vermijden. Het callable patroon biedt duidelijkere controleflow en betere compatibiliteit met async Django.

Veelgestelde Django Middleware Sollicitatievragen

Technische sollicitaties bevatten vaak middleware-vragen om begrip van Django's request-levenscyclus te beoordelen. Deze vragen verschijnen regelmatig in senior Django developer sollicitaties.

V: Wat is het verschil tussen middleware-volgorde en de uitvoeringsvolgorde voor responses?

Middleware verwerkt requests van boven naar beneden door MIDDLEWARE, maar verwerkt responses van onder naar boven. Stel het voor als een ui: de buitenste middleware is de eerste die de request ziet en de laatste die de response ziet.

V: Hoe werkt middleware short-circuiting?

Wanneer middleware een HttpResponse retourneert in plaats van get_response() aan te roepen, bereikt de request nooit binnenste middleware of de view. De response passeert nog steeds alle buitenste middleware op de terugweg. Dit gedrag verschilt van de verouderde MIDDLEWARE_CLASSES instelling, waar alle process_response methoden werden uitgevoerd ongeacht short-circuiting.

V: Wanneer moet middleware toegang hebben tot request.user?

Alleen nadat AuthenticationMiddleware is uitgevoerd. Toegang tot request.user voordat de authenticatie-middleware het koppelt, genereert een AttributeError. Plaats custom middleware die gebruikersinformatie nodig heeft na AuthenticationMiddleware in de MIDDLEWARE-lijst.

V: Hoe maak je middleware async-compatibel?

Stel async_capable = True in op de middleware-klasse en implementeer __call__ als een async methode met await get_response(request). Voor middleware die moet werken in zowel sync als async contexten, gebruik @sync_and_async_middleware en controleer iscoroutinefunction(get_response) om dienovereenkomstig te branchen.

Begin met oefenen!

Test je kennis met onze gespreksimulatoren en technische tests.

Django Middleware Beheersen voor Productie en Sollicitaties

Django middleware beheert cross-cutting concerns die de gehele request-levenscyclus overspannen. De belangrijkste punten voor het werken met middleware in Django 6.0:

  • Middleware wordt uitgevoerd in een ui-patroon: request stroomt van boven naar beneden, response stroomt van onder naar boven
  • Stel async_capable = True in voor async-native middleware in ASGI deployments om thread pool overhead te vermijden
  • Gebruik process_view om view metadata te inspecteren voor uitvoering, process_exception voor gecentraliseerde error logging
  • Request ID middleware maakt log-correlatie mogelijk over gedistribueerde services, een veelvoorkomende vereiste in productie
  • LoginRequiredMiddleware inverteert het authenticatiepatroon: views zijn standaard beschermd, publieke views worden expliciet vrijgesteld
  • De deprecated django.utils.deprecation.MiddlewareMixin verhuist naar django.middleware.MiddlewareMixin in Django 6.2
  • Middleware-volgorde bepaalt welke componenten request.user, sessiegegevens en andere request-attributen zien

Voor diepere behandeling van Django ORM en REST framework patronen, zie de Django ORM optimalisatiegids.

Dagelijkse challenge

Zie jij de bug in Django?

Een echt codefragment, een verborgen bug, één poging per dag. Zonder account uit te proberen.

Anthony Fillion-Maillet

Geschreven door

Anthony Fillion-Maillet

Oprichter van SharpSkill

Al meer dan 10 jaar fullstack-ontwikkelaar. Hij leidt SharpSkill en staat in voor alles wat hier verschijnt.

Bijgewerkt op 18 september 2026

Tags

#django
#middleware
#logging
#python
#interview

Delen

Gerelateerde artikelen