# Advanced Django Middleware 2026: Custom Middleware, Logging, dan Pertanyaan Interview > Panduan lengkap Django middleware di tahun 2026 mencakup pembuatan custom middleware, implementasi logging yang efektif, serta pertanyaan interview yang sering muncul untuk developer Django tingkat senior. - Published: 2026-09-18 - Updated: 2026-09-18 - Author: Anthony Fillion-Maillet - Tags: django, middleware, python, logging, interview - Reading time: 12 min --- Django middleware berperan sebagai lapisan penting dalam setiap siklus request-response, namun banyak developer yang memperlakukannya sebagai kotak hitam. Pemahaman mendalam tentang eksekusi middleware, kapan harus menulis custom middleware, dan bagaimana mengimplementasikan logging pada level middleware menjadi pembeda antara developer Django senior dan junior dalam technical interview. > **Django 6.0 Middleware** > > Django 6.0 mendukung penuh async middleware dengan sintaks async/await native. Atur `async_capable = True` dan `sync_capable = False` pada middleware class untuk menangani request tanpa overhead thread. ## Eksekusi Django Middleware dalam Request-Response Cycle Middleware di Django mengikuti model "onion" atau bawang. Ketika request tiba, ia melewati setiap middleware di `MIDDLEWARE` dari atas ke bawah. Ketika view mengembalikan response, response tersebut melewati middleware dari bawah ke atas. Urutan ini sangat penting: middleware yang membutuhkan data session harus dijalankan setelah `SessionMiddleware`. Konfigurasi `MIDDLEWARE` default di 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", ] ``` Setiap middleware dapat memotong rantai dengan mengembalikan `HttpResponse` secara langsung tanpa memanggil `get_response()`. Ketika ini terjadi, middleware bagian dalam dan view tidak akan pernah dieksekusi, tetapi middleware bagian luar tetap memproses response. ## Menulis Custom Middleware Berbasis Class di Django 6.0 Pola middleware modern memerlukan class dengan method `__init__` dan `__call__`. Method `__init__` berjalan sekali ketika server dimulai, sedangkan `__call__` berjalan untuk setiap request. ```python # middleware/timing.py import time import logging logger = logging.getLogger(__name__) class RequestTimingMiddleware: """Mencatat waktu yang dibutuhkan untuk memproses setiap request.""" def __init__(self, get_response): # Dipanggil sekali ketika server dimulai self.get_response = get_response def __call__(self, request): # Kode sebelum view dieksekusi start_time = time.perf_counter() # Memanggil middleware berikutnya atau view response = self.get_response(request) # Kode setelah view dieksekusi duration_ms = (time.perf_counter() - start_time) * 1000 logger.info( "Request %s %s selesai dalam %.2fms", request.method, request.path, duration_ms ) return response ``` Daftarkan middleware di `settings.py` dengan menambahkan import path-nya ke `MIDDLEWARE`. Posisi sangat penting: tempatkan timing middleware di awal daftar untuk mengukur lifecycle request secara penuh. ## Async Middleware untuk Aplikasi Django High-Concurrency Django 6.0 menangani async request secara native. Untuk aplikasi yang berjalan di bawah ASGI dengan async views, sync middleware menciptakan bottleneck performa karena Django membungkus sync middleware dalam thread pool executors. Menulis async middleware menghilangkan overhead ini. ```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 untuk 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() # Await middleware berikutnya atau async view response = await self.get_response(request) duration_ms = (time.perf_counter() - start_time) * 1000 logger.info( "Async request %s %s selesai dalam %.2fms", request.method, request.path, duration_ms ) return response ``` Decorator `@sync_and_async_middleware` dari `django.utils.decorators` membuat middleware yang menangani request sync dan async dengan memeriksa `iscoroutinefunction(get_response)` saat runtime. ## Implementasi Request ID Logging Middleware Mengorelasikan log di sistem terdistribusi memerlukan identifier unik per request. Pola ini sering muncul dalam [pertanyaan interview Django](/technologies/django/interview-questions/django-middleware) karena mendemonstrasikan pemahaman tentang middleware, logging, dan debugging sistem produksi. ```python # middleware/request_id.py import uuid import logging class RequestIDMiddleware: """Melampirkan request ID unik ke setiap request untuk korelasi log.""" def __init__(self, get_response): self.get_response = get_response def __call__(self, request): # Generate atau ekstrak request ID dari header request_id = request.headers.get("X-Request-ID") if not request_id: request_id = str(uuid.uuid4()) # Lampirkan ke objek request untuk akses di views request.request_id = request_id response = self.get_response(request) # Tambahkan request ID ke response headers response["X-Request-ID"] = request_id return response ``` Untuk menyertakan `request_id` di semua pesan log, buat logging filter khusus: ```python # logging_filters.py import logging class RequestIDFilter(logging.Filter): """Menyuntikkan request_id ke dalam 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 ``` Konfigurasikan filter di `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", }, } ``` ## Hook Method Middleware untuk Kontrol Detail Selain `__call__`, Django middleware mendukung tiga hook method: `process_view`, `process_exception`, dan `process_template_response`. Method ini memberikan kontrol pada titik-titik spesifik dalam lifecycle request. ### process_view untuk Logika Pre-Execution ```python # middleware/permission_check.py from django.http import HttpResponseForbidden class PermissionCheckMiddleware: """Memeriksa permission sebelum eksekusi 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): # Akses metadata view required_permission = getattr(view_func, "required_permission", None) if required_permission: if not request.user.has_perm(required_permission): return HttpResponseForbidden("Permission denied") # Return None untuk melanjutkan ke view return None ``` Pola ini memungkinkan mendekorasi views dengan permission requirements: ```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): # Logika view pass ``` ### process_exception untuk Error Handling Terpusat ```python # middleware/error_tracking.py import logging import traceback logger = logging.getLogger(__name__) class ErrorTrackingMiddleware: """Mencatat exception dengan konteks lengkap sebelum Django menanganinya.""" 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( "Unhandled exception di %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), } ) # Return None untuk membiarkan Django menangani exception return None ``` Method `process_exception` middleware dieksekusi dalam urutan terbalik. Jika salah satu mengembalikan `HttpResponse`, middleware yang lebih awal dalam stack tidak akan melihat exception tersebut. ## Update Security Middleware Django 6.0 Django 6.0 dilengkapi dengan beberapa perbaikan keamanan untuk `UpdateCacheMiddleware`. Menurut [Django security releases dari 2026](https://www.djangoproject.com/weblog/2026/jun/03/security-releases/), response dengan `Cache-Control: private` yang menggunakan mixed case salah di-cache, dan response terhadap request dengan header `Authorization` dapat disimpan di shared caches. LoginRequiredMiddleware, yang diperkenalkan di Django 5.1, memaksa autentikasi site-wide: ```python # settings.py MIDDLEWARE = [ # ... middleware lainnya "django.contrib.auth.middleware.LoginRequiredMiddleware", ] # Kecualikan view tertentu from django.contrib.auth.decorators import login_not_required @login_not_required def public_view(request): return HttpResponse("Konten publik") ``` Ini membalikkan pola tradisional mendekorasi protected views dengan `@login_required`. Untuk aplikasi di mana sebagian besar views memerlukan autentikasi, ini mengurangi boilerplate dan mencegah eksposur endpoint protected secara tidak sengaja. ## MiddlewareMixin dan Migrasi dari Legacy Middleware `MiddlewareMixin` menjembatani middleware gaya lama (menggunakan method `process_request` dan `process_response`) ke pola callable baru. Perhatikan bahwa `django.utils.deprecation.MiddlewareMixin` sudah deprecated dan akan dihapus di Django 6.2. Gunakan `django.middleware.MiddlewareMixin` sebagai gantinya. ```python # middleware/legacy_style.py from django.middleware import MiddlewareMixin class LegacyStyleMiddleware(MiddlewareMixin): """Middleware menggunakan pola hook-based legacy.""" def process_request(self, request): # Dipanggil sebelum view, return None untuk melanjutkan request.custom_attribute = "value" return None def process_response(self, request, response): # Dipanggil setelah view, harus return response response["X-Custom-Header"] = "middleware-added" return response ``` Untuk middleware baru, hindari `MiddlewareMixin`. Pola callable memberikan kontrol flow yang lebih jelas dan kompatibilitas lebih baik dengan async Django. ## Pertanyaan Interview Django Middleware yang Umum Technical interview sering menyertakan pertanyaan middleware untuk menilai pemahaman tentang lifecycle request Django. Pertanyaan-pertanyaan ini sering muncul dalam [interview developer Django senior](/blog/django/django-interview-orm-middleware-drf). **T: Apa perbedaan antara urutan middleware dan urutan eksekusi untuk response?** Middleware memproses request dari atas ke bawah melalui `MIDDLEWARE` tetapi memproses response dari bawah ke atas. Bayangkan seperti bawang: middleware terluar adalah yang pertama melihat request dan terakhir melihat response. **T: Bagaimana cara kerja middleware short-circuiting?** Ketika middleware mengembalikan `HttpResponse` alih-alih memanggil `get_response()`, request tidak pernah mencapai middleware dalam atau view. Response tetap melewati semua middleware luar dalam perjalanan kembali. Perilaku ini berbeda dari setting `MIDDLEWARE_CLASSES` legacy, di mana semua method `process_response` berjalan terlepas dari short-circuiting. **T: Kapan middleware harus mengakses `request.user`?** Hanya setelah `AuthenticationMiddleware` berjalan. Mengakses `request.user` sebelum authentication middleware melampirkannya akan menimbulkan `AttributeError`. Tempatkan custom middleware yang membutuhkan informasi user setelah `AuthenticationMiddleware` dalam daftar `MIDDLEWARE`. **T: Bagaimana cara membuat middleware async-compatible?** Atur `async_capable = True` pada middleware class dan implementasikan `__call__` sebagai async method menggunakan `await get_response(request)`. Untuk middleware yang harus bekerja di konteks sync dan async, gunakan `@sync_and_async_middleware` dan periksa `iscoroutinefunction(get_response)` untuk bercabang sesuai kebutuhan. ## Menguasai Django Middleware untuk Produksi dan Interview Django middleware mengontrol cross-cutting concerns yang mencakup seluruh lifecycle request. Poin-poin penting untuk bekerja dengan middleware di Django 6.0: - Middleware dieksekusi dalam pola onion: request mengalir dari atas ke bawah, response mengalir dari bawah ke atas - Atur `async_capable = True` untuk async-native middleware di deployment ASGI untuk menghindari overhead thread pool - Gunakan `process_view` untuk memeriksa metadata view sebelum eksekusi, `process_exception` untuk logging error terpusat - Request ID middleware memungkinkan korelasi log di layanan terdistribusi, kebutuhan umum di produksi - `LoginRequiredMiddleware` membalikkan pola autentikasi: views dilindungi secara default, views publik dikecualikan secara eksplisit - `django.utils.deprecation.MiddlewareMixin` yang deprecated pindah ke `django.middleware.MiddlewareMixin` di Django 6.2 - Urutan middleware menentukan komponen mana yang melihat `request.user`, data session, dan atribut request lainnya Untuk pembahasan lebih mendalam tentang pola Django ORM dan REST framework, lihat [panduan optimasi Django ORM](/blog/django/django-orm-optimizing-queries). --- Source: SharpSkill (https://sharpskill.dev), tech interview preparation for your real stack. HTML version of this page: https://sharpskill.dev/id/blog/django/django-advanced-middleware-logging-2026