Thứ tự MIDDLEWARE quyết định thứ tự bao bọc — middleware ở top chạy đầu tiên trên request và cuối cùng trên response. Đặt sai thì middleware sau không thấy thứ middleware trước đã set, hoặc tệ hơn là check security bị bypass.
Thứ tự mặc định của Django, kèm lý do:
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware', # HTTPS redirect sớm nhất
'django.contrib.sessions.middleware.SessionMiddleware', # set request.session
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware', # cần session đã set
'django.contrib.auth.middleware.AuthenticationMiddleware', # set request.user, cần session
'django.contrib.messages.middleware.MessageMiddleware', # cần session
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]Hai bug điển hình: đặt AuthenticationMiddleware trước SessionMiddleware thì request.user luôn là AnonymousMiddleware vì không đọc được session. Đặt logger custom trước SecurityMiddleware thì log nhận luôn cả request đáng lẽ bị redirect HTTPS.
Quy tắc đơn giản: custom middleware đụng request.user phải đặt sau AuthenticationMiddleware; đụng request.session phải sau SessionMiddleware. Nếu có dependency lẫn nhau, viết comment ngắn ngay trong settings.py để người sau không vô tình đổi thứ tự.
The MIDDLEWARE order controls wrapping order — the top runs first on request and last on response. Wrong order → later middleware does not see what earlier set, or security checks get bypassed.
Django's default order and why:
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware', # HTTPS redirect first
'django.contrib.sessions.middleware.SessionMiddleware', # sets request.session
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware', # needs session set
'django.contrib.auth.middleware.AuthenticationMiddleware', # sets request.user, needs session
'django.contrib.messages.middleware.MessageMiddleware', # needs session
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]Classic bugs: putting AuthenticationMiddleware before SessionMiddleware → request.user is always AnonymousUser because there is no session to read. Putting a custom logger before SecurityMiddleware → it logs requests that should have been HTTPS-redirected.
Pitfall: Custom middleware that touches request.user must sit after AuthenticationMiddleware; touching request.session must come after SessionMiddleware. If there is a real dependency, leave a comment in settings so the next person does not silently reorder.