# Django Middleware ขั้นสูง 2026: Custom Middleware, Logging และคำถามสัมภาษณ์งาน > คู่มือฉบับสมบูรณ์เกี่ยวกับ Django middleware ในปี 2026 ครอบคลุมการสร้าง custom middleware การใช้งาน logging อย่างมีประสิทธิภาพ และคำถามสัมภาษณ์ที่พบบ่อยสำหรับนักพัฒนา Django ระดับ 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 อยู่ที่แกนกลางของทุก request-response cycle แต่นักพัฒนาหลายคนยังคงมองว่ามันเป็นกล่องดำ การเข้าใจว่า middleware ทำงานอย่างไร เมื่อไหร่ควรเขียน custom middleware และวิธีการ implement logging ในระดับ middleware เป็นสิ่งที่แยกแยะนักพัฒนา Django ระดับ senior ออกจาก junior ในการสัมภาษณ์งานด้านเทคนิค > **Django 6.0 Middleware** > > Django 6.0 รองรับ async middleware อย่างสมบูรณ์ด้วย syntax async/await แบบ native ตั้งค่า `async_capable = True` และ `sync_capable = False` บน middleware class เพื่อจัดการ request โดยไม่มี overhead จาก thread ## วิธีการทำงานของ Django Middleware ใน Request-Response Cycle Middleware ใน Django ใช้โมเดล "onion" (หัวหอม) เมื่อ request มาถึง มันจะผ่านแต่ละ middleware ใน `MIDDLEWARE` จากบนลงล่าง เมื่อ view ส่งคืน response นั้น response จะผ่านกลับผ่าน middleware จากล่างขึ้นบน ลำดับนี้มีความสำคัญ: middleware ที่ต้องการข้อมูล session ต้องทำงานหลัง `SessionMiddleware` การกำหนดค่า `MIDDLEWARE` เริ่มต้นใน 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", ] ``` แต่ละ middleware สามารถตัดสายโซ่ได้โดยการส่งคืน `HttpResponse` โดยตรงแทนที่จะเรียก `get_response()` เมื่อสิ่งนี้เกิดขึ้น middleware ด้านในและ view จะไม่ถูกเรียกใช้ แต่ middleware ด้านนอกยังคงประมวลผล response ## การเขียน Custom Middleware แบบ Class-Based ใน Django 6.0 รูปแบบ middleware สมัยใหม่ต้องการ class ที่มี method `__init__` และ `__call__` method `__init__` ทำงานครั้งเดียวเมื่อ server เริ่มต้น ในขณะที่ `__call__` ทำงานสำหรับทุก request ```python # middleware/timing.py import time import logging logger = logging.getLogger(__name__) class RequestTimingMiddleware: """บันทึกเวลาที่ใช้ในการประมวลผลแต่ละ request""" def __init__(self, get_response): # เรียกครั้งเดียวเมื่อ server เริ่มต้น self.get_response = get_response def __call__(self, request): # โค้ดก่อนที่ view จะทำงาน start_time = time.perf_counter() # เรียก middleware ถัดไปหรือ view response = self.get_response(request) # โค้ดหลังจาก view ทำงานแล้ว duration_ms = (time.perf_counter() - start_time) * 1000 logger.info( "Request %s %s เสร็จสิ้นใน %.2fms", request.method, request.path, duration_ms ) return response ``` ลงทะเบียน middleware ใน `settings.py` โดยเพิ่ม import path ลงใน `MIDDLEWARE` ตำแหน่งมีความสำคัญ: วาง timing middleware ไว้ต้นรายการเพื่อวัด lifecycle ของ request ทั้งหมด ## Async Middleware สำหรับแอปพลิเคชัน Django ที่มี High-Concurrency Django 6.0 จัดการ async request แบบ native สำหรับแอปพลิเคชันที่ทำงานภายใต้ ASGI พร้อมกับ async views sync middleware จะสร้างคอขวดด้านประสิทธิภาพเนื่องจาก Django จะ wrap sync middleware ใน thread pool executors การเขียน async middleware จะกำจัด 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 สำหรับการ deploy 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 ถัดไปหรือ async view response = await self.get_response(request) duration_ms = (time.perf_counter() - start_time) * 1000 logger.info( "Async request %s %s เสร็จสิ้นใน %.2fms", request.method, request.path, duration_ms ) return response ``` Decorator `@sync_and_async_middleware` จาก `django.utils.decorators` สร้าง middleware ที่จัดการทั้ง request แบบ sync และ async โดยตรวจสอบ `iscoroutinefunction(get_response)` ใน runtime ## การ Implement Request ID Logging Middleware การเชื่อมโยง log ในระบบแบบกระจายต้องการ identifier ที่ไม่ซ้ำกันต่อ request รูปแบบนี้ปรากฏบ่อยใน[คำถามสัมภาษณ์ Django](/technologies/django/interview-questions/django-middleware) เพราะมันแสดงให้เห็นถึงความเข้าใจเกี่ยวกับ middleware logging และการ debug ระบบ production ```python # middleware/request_id.py import uuid import logging class RequestIDMiddleware: """แนบ request ID ที่ไม่ซ้ำกันกับทุก request เพื่อการเชื่อมโยง log""" def __init__(self, get_response): self.get_response = get_response def __call__(self, request): # สร้างหรือดึง request ID จาก header request_id = request.headers.get("X-Request-ID") if not request_id: request_id = str(uuid.uuid4()) # แนบกับ request object เพื่อเข้าถึงใน views request.request_id = request_id response = self.get_response(request) # เพิ่ม request ID ลงใน response headers response["X-Request-ID"] = request_id return response ``` เพื่อรวม `request_id` ในทุกข้อความ log ให้สร้าง logging filter แบบกำหนดเอง: ```python # logging_filters.py import logging class RequestIDFilter(logging.Filter): """ฉีด request_id เข้าไปใน 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 ``` กำหนดค่า filter ใน `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 Methods ของ Middleware สำหรับการควบคุมอย่างละเอียด นอกเหนือจาก `__call__` แล้ว Django middleware ยังรองรับสาม hook methods: `process_view`, `process_exception` และ `process_template_response` ซึ่งให้การควบคุมที่จุดเฉพาะใน lifecycle ของ request ### process_view สำหรับ Logic ก่อนการทำงาน ```python # middleware/permission_check.py from django.http import HttpResponseForbidden class PermissionCheckMiddleware: """ตรวจสอบ permission ก่อนที่ 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): # เข้าถึง 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 เพื่อดำเนินการต่อไปยัง view return None ``` รูปแบบนี้ช่วยให้สามารถ decorate views ด้วยข้อกำหนด permission: ```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 logic pass ``` ### process_exception สำหรับ Error Handling แบบรวมศูนย์ ```python # middleware/error_tracking.py import logging import traceback logger = logging.getLogger(__name__) class ErrorTrackingMiddleware: """บันทึก exception พร้อมบริบทเต็มก่อนที่ Django จะจัดการ""" 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 ใน %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 เพื่อให้ Django จัดการ exception return None ``` Methods `process_exception` ของ middleware ทำงานในลำดับกลับกัน หากตัวหนึ่งส่งคืน `HttpResponse` middleware ที่อยู่ก่อนหน้าใน stack จะไม่เห็น exception ## การอัพเดต Security Middleware ใน Django 6.0 Django 6.0 มาพร้อมกับการแก้ไขด้านความปลอดภัยหลายรายการสำหรับ `UpdateCacheMiddleware` ตาม[Django security releases จาก 2026](https://www.djangoproject.com/weblog/2026/jun/03/security-releases/) response ที่มี `Cache-Control: private` ที่ใช้ mixed case ถูก cache อย่างไม่ถูกต้อง และ response สำหรับ request ที่มี header `Authorization` อาจถูกเก็บใน shared caches LoginRequiredMiddleware ซึ่งเปิดตัวใน Django 5.1 บังคับใช้การยืนยันตัวตนทั่วทั้ง site: ```python # settings.py MIDDLEWARE = [ # ... middleware อื่นๆ "django.contrib.auth.middleware.LoginRequiredMiddleware", ] # ยกเว้น view เฉพาะ from django.contrib.auth.decorators import login_not_required @login_not_required def public_view(request): return HttpResponse("เนื้อหาสาธารณะ") ``` สิ่งนี้กลับด้านรูปแบบดั้งเดิมของการ decorate protected views ด้วย `@login_required` สำหรับแอปพลิเคชันที่ views ส่วนใหญ่ต้องการการยืนยันตัวตน สิ่งนี้ลด boilerplate และป้องกันการเปิดเผย endpoint ที่ได้รับการป้องกันโดยไม่ตั้งใจ ## MiddlewareMixin และการ Migrate จาก Legacy Middleware `MiddlewareMixin` เชื่อมต่อ middleware รูปแบบเก่า (ใช้ method `process_request` และ `process_response`) กับรูปแบบ callable ใหม่ โปรดทราบว่า `django.utils.deprecation.MiddlewareMixin` ถูก deprecated และจะถูกลบออกใน Django 6.2 ให้ใช้ `django.middleware.MiddlewareMixin` แทน ```python # middleware/legacy_style.py from django.middleware import MiddlewareMixin class LegacyStyleMiddleware(MiddlewareMixin): """Middleware ที่ใช้รูปแบบ hook-based แบบ legacy""" def process_request(self, request): # เรียกก่อน view, return None เพื่อดำเนินการต่อ request.custom_attribute = "value" return None def process_response(self, request, response): # เรียกหลัง view, ต้อง return response response["X-Custom-Header"] = "middleware-added" return response ``` สำหรับ middleware ใหม่ ให้หลีกเลี่ยง `MiddlewareMixin` รูปแบบ callable ให้การควบคุมการไหลที่ชัดเจนกว่าและเข้ากันได้ดีกว่ากับ async Django ## คำถามสัมภาษณ์เกี่ยวกับ Django Middleware ที่พบบ่อย การสัมภาษณ์ทางเทคนิคมักรวมคำถามเกี่ยวกับ middleware เพื่อประเมินความเข้าใจเกี่ยวกับ lifecycle ของ request ใน Django คำถามเหล่านี้มักปรากฏใน[การสัมภาษณ์นักพัฒนา Django ระดับ senior](/blog/django/django-interview-orm-middleware-drf) **ถ: อะไรคือความแตกต่างระหว่างลำดับ middleware และลำดับการทำงานสำหรับ response?** Middleware ประมวลผล request จากบนลงล่างผ่าน `MIDDLEWARE` แต่ประมวลผล response จากล่างขึ้นบน ลองนึกภาพเหมือนหัวหอม: middleware นอกสุดเป็นตัวแรกที่เห็น request และเป็นตัวสุดท้ายที่เห็น response **ถ: Middleware short-circuiting ทำงานอย่างไร?** เมื่อ middleware ส่งคืน `HttpResponse` แทนที่จะเรียก `get_response()` request จะไม่ไปถึง middleware ด้านในหรือ view response ยังคงผ่าน middleware ด้านนอกทั้งหมดในทางกลับ พฤติกรรมนี้แตกต่างจากการตั้งค่า `MIDDLEWARE_CLASSES` แบบ legacy ซึ่ง method `process_response` ทั้งหมดจะทำงานโดยไม่คำนึงถึง short-circuiting **ถ: เมื่อไหร่ middleware ควรเข้าถึง `request.user`?** หลังจาก `AuthenticationMiddleware` ทำงานแล้วเท่านั้น การเข้าถึง `request.user` ก่อนที่ authentication middleware จะแนบมันจะทำให้เกิด `AttributeError` วาง custom middleware ที่ต้องการข้อมูลผู้ใช้หลัง `AuthenticationMiddleware` ในรายการ `MIDDLEWARE` **ถ: จะทำให้ middleware รองรับ async ได้อย่างไร?** ตั้งค่า `async_capable = True` บน middleware class และ implement `__call__` เป็น async method โดยใช้ `await get_response(request)` สำหรับ middleware ที่ต้องทำงานในทั้งบริบท sync และ async ให้ใช้ `@sync_and_async_middleware` และตรวจสอบ `iscoroutinefunction(get_response)` เพื่อแยกสาขาตามความเหมาะสม ## การเชี่ยวชาญ Django Middleware สำหรับ Production และการสัมภาษณ์ Django middleware ควบคุม cross-cutting concerns ที่ครอบคลุมทั้ง lifecycle ของ request ประเด็นสำคัญในการทำงานกับ middleware ใน Django 6.0: - Middleware ทำงานในรูปแบบ onion: request ไหลจากบนลงล่าง response ไหลจากล่างขึ้นบน - ตั้งค่า `async_capable = True` สำหรับ async-native middleware ใน deployment ASGI เพื่อหลีกเลี่ยง overhead ของ thread pool - ใช้ `process_view` เพื่อตรวจสอบ metadata ของ view ก่อนการทำงาน ใช้ `process_exception` สำหรับ logging error แบบรวมศูนย์ - Request ID middleware ช่วยให้สามารถเชื่อมโยง log ข้าม service แบบกระจาย ซึ่งเป็นข้อกำหนดทั่วไปใน production - `LoginRequiredMiddleware` กลับด้านรูปแบบการยืนยันตัวตน: views ได้รับการป้องกันโดยค่าเริ่มต้น views สาธารณะได้รับการยกเว้นอย่างชัดเจน - `django.utils.deprecation.MiddlewareMixin` ที่ deprecated จะย้ายไปยัง `django.middleware.MiddlewareMixin` ใน Django 6.2 - ลำดับ middleware กำหนดว่า component ใดจะเห็น `request.user` ข้อมูล session และ attribute อื่นๆ ของ request สำหรับการครอบคลุมเชิงลึกเกี่ยวกับรูปแบบ Django ORM และ REST framework โปรดดู[คู่มือการปรับปรุง 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/th/blog/django/django-advanced-middleware-logging-2026