Django Middleware ขั้นสูง 2026: Custom Middleware, Logging และคำถามสัมภาษณ์งาน

คู่มือฉบับสมบูรณ์เกี่ยวกับ Django middleware ในปี 2026 ครอบคลุมการสร้าง custom middleware การใช้งาน logging อย่างมีประสิทธิภาพ และคำถามสัมภาษณ์ที่พบบ่อยสำหรับนักพัฒนา Django ระดับ senior

ไดอะแกรมสถาปัตยกรรม Django middleware แสดงการไหลของ request-response

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 เพราะมันแสดงให้เห็นถึงความเข้าใจเกี่ยวกับ 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",
    },
}

พร้อมที่จะพิชิตการสัมภาษณ์ Django แล้วหรือยังครับ?

ฝึกฝนด้วยตัวจำลองแบบโต้ตอบ, flashcards และแบบทดสอบเทคนิคครับ

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

ถ: อะไรคือความแตกต่างระหว่างลำดับ 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

ชาเลนจ์ประจำวัน

คุณหาบั๊กใน Django เจอไหม

โค้ดจริงหนึ่งชิ้น บั๊กที่ซ่อนอยู่หนึ่งจุด วันละหนึ่งครั้ง ลองได้โดยไม่ต้องมีบัญชี

Anthony Fillion-Maillet

เขียนโดย

Anthony Fillion-Maillet

ผู้ก่อตั้ง SharpSkill

เป็นนักพัฒนาฟูลสแตกมากว่า 10 ปี ดูแล SharpSkill และรับผิดชอบทุกสิ่งที่เผยแพร่ที่นี่

อัปเดตเมื่อ 18 กันยายน 2569

แท็ก

#django
#middleware
#python
#logging
#interview

แชร์

บทความที่เกี่ยวข้อง

Django 5.2 custom middleware และ signal handling คู่มือเตรียมสัมภาษณ์

Django 5.2 Custom Middleware และ Signal Handling: คู่มือเตรียมสัมภาษณ์เชิงเทคนิค

คู่มือเชิงลึก Django 5.2 custom middleware และ signal handling สำหรับการสัมภาษณ์เชิงเทคนิค ครอบคลุม request pipeline, async middleware, post_save, pre_save, custom signals และแนวทางปฏิบัติที่ดีสำหรับ production

เตรียมสัมภาษณ์งาน Django ครอบคลุม ORM, Middleware และแนวคิด Django REST Framework

คำถามสัมภาษณ์งาน Django: ORM, Middleware และ DRF เจาะลึก

คำถามสัมภาษณ์งาน Django ครอบคลุมการปรับแต่ง ORM ด้วย select_related, prefetch_related และโหมด FETCH_PEERS ของ Django 6.1, สถาปัตยกรรม middleware, ประสิทธิภาพ serializer ของ Django REST Framework, permissions และรูปแบบ pagination

บทช่วยสอน Django 6.0 composite primary key และ background task

Django 6.0 ในปี 2026: Composite Primary Key, Background Task และคำถามสัมภาษณ์งาน

คู่มือฉบับสมบูรณ์เกี่ยวกับ Django 6.0 ครอบคลุม composite primary key, framework background task ในตัว, template partial, CSP middleware พร้อมตัวอย่างโค้ดจริงและการเตรียมตัวสัมภาษณ์