Django ミドルウェア完全ガイド 2026:カスタムミドルウェア、ロギング実装と面接対策
Django 6.0のミドルウェアを徹底解説。カスタムミドルウェアの作成方法、非同期ミドルウェア、リクエストIDロギング、そして技術面接で頻出の質問と回答を詳しく説明します。

Djangoミドルウェアは、すべてのリクエスト・レスポンスサイクルの中核を担っています。しかし、多くの開発者はミドルウェアをブラックボックスとして扱いがちです。ミドルウェアの実行順序、カスタムミドルウェアの作成タイミング、ミドルウェアレベルでのロギング実装を理解することは、技術面接においてシニアDjango開発者とジュニア開発者を区別する重要なポイントとなります。
Django 6.0では、ネイティブのasync/await構文による非同期ミドルウェアが完全にサポートされています。ミドルウェアクラスにasync_capable = Trueとsync_capable = Falseを設定することで、スレッドオーバーヘッドなしでリクエストを処理できます。
Djangoミドルウェアのリクエスト・レスポンスサイクルにおける実行順序
Djangoのミドルウェアは「オニオン(玉ねぎ)モデル」に従って動作します。リクエストが到着すると、MIDDLEWAREリストの上から下へ各ミドルウェアを通過します。ビューがレスポンスを返すと、レスポンスは下から上へミドルウェアを逆順に通過します。この順序は重要であり、セッションデータが必要なミドルウェアはSessionMiddlewareの後に配置する必要があります。
Django 6.0のデフォルトMIDDLEWARE設定は以下の通りです:
# 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",
]各ミドルウェアは、get_response()を呼び出す代わりにHttpResponseを直接返すことで、チェーンをショートサーキット(短絡)できます。この場合、内側のミドルウェアとビューは実行されませんが、外側のミドルウェアは引き続きレスポンスを処理します。
Django 6.0でのクラスベースカスタムミドルウェアの作成
現代のミドルウェアパターンでは、__init__と__call__メソッドを持つクラスが必要です。__init__メソッドはサーバー起動時に一度だけ実行され、__call__はリクエストごとに実行されます。
# middleware/timing.py
import time
import logging
logger = logging.getLogger(__name__)
class RequestTimingMiddleware:
"""Logs the time taken to process each request."""
def __init__(self, get_response):
# Called once when the server starts
self.get_response = get_response
def __call__(self, request):
# Code before the view executes
start_time = time.perf_counter()
# Call the next middleware or view
response = self.get_response(request)
# Code after the view executes
duration_ms = (time.perf_counter() - start_time) * 1000
logger.info(
"Request %s %s completed in %.2fms",
request.method,
request.path,
duration_ms
)
return responseミドルウェアをsettings.pyに登録するには、インポートパスをMIDDLEWAREに追加します。配置位置は重要であり、タイミングミドルウェアはリクエストライフサイクル全体を計測するためにリストの早い位置に配置します。
高並行性Djangoアプリケーション向け非同期ミドルウェア
Django 6.0は非同期リクエストをネイティブに処理します。ASGIで非同期ビューを実行するアプリケーションでは、同期ミドルウェアがパフォーマンスボトルネックを引き起こします。これはDjangoが同期ミドルウェアをスレッドプールエグゼキュータでラップするためです。非同期ミドルウェアを作成することで、このオーバーヘッドを排除できます。
# middleware/async_timing.py
import time
import logging
from asgiref.sync import iscoroutinefunction, markcoroutinefunction
logger = logging.getLogger(__name__)
class AsyncRequestTimingMiddleware:
"""Async-native timing middleware for 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 the next middleware or async view
response = await self.get_response(request)
duration_ms = (time.perf_counter() - start_time) * 1000
logger.info(
"Async request %s %s completed in %.2fms",
request.method,
request.path,
duration_ms
)
return responsedjango.utils.decoratorsの@sync_and_async_middlewareデコレータは、ランタイムでiscoroutinefunction(get_response)をチェックすることで、同期と非同期の両方のリクエストを処理するミドルウェアを作成します。
リクエストIDロギングミドルウェアの実装
分散システム間でログを相関させるには、リクエストごとに一意の識別子が必要です。このパターンはDjango面接質問で頻繁に登場します。ミドルウェア、ロギング、本番システムのデバッグに関する理解を示すためです。
# middleware/request_id.py
import uuid
import logging
class RequestIDMiddleware:
"""Attaches a unique request ID to every request for log correlation."""
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
# Generate or extract request ID from header
request_id = request.headers.get("X-Request-ID")
if not request_id:
request_id = str(uuid.uuid4())
# Attach to request object for access in views
request.request_id = request_id
response = self.get_response(request)
# Add request ID to response headers
response["X-Request-ID"] = request_id
return responseすべてのログメッセージにrequest_idを含めるには、カスタムロギングフィルターを作成します:
# logging_filters.py
import logging
class RequestIDFilter(logging.Filter):
"""Injects request_id into log records."""
def filter(self, record):
from django.middleware.request_id import local
record.request_id = getattr(local, "request_id", "no-request-id")
return Truesettings.pyでフィルターを設定します:
# 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、技術テストで練習しましょう。
きめ細かな制御のためのミドルウェアフックメソッド
__call__以外にも、Djangoミドルウェアは3つのフックメソッドをサポートしています:process_view、process_exception、process_template_response。これらはリクエストライフサイクルの特定のポイントで制御を提供します。
実行前ロジック用のprocess_view
# middleware/permission_check.py
from django.http import HttpResponseForbidden
class PermissionCheckMiddleware:
"""Checks permissions before view execution."""
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):
# Access view metadata
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 to continue to the view
return Noneこのパターンにより、ビューにパーミッション要件をデコレートできます:
# 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
# middleware/error_tracking.py
import logging
import traceback
logger = logging.getLogger(__name__)
class ErrorTrackingMiddleware:
"""Logs exceptions with full context before Django handles them."""
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 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),
}
)
# Return None to let Django handle the exception
return Noneミドルウェアのprocess_exceptionメソッドは逆順で実行されます。いずれかがHttpResponseを返すと、リストの前方にあるミドルウェアは例外を見ることができません。
Django 6.0セキュリティミドルウェアのアップデート
Django 6.0ではUpdateCacheMiddlewareにいくつかのセキュリティ修正が含まれています。2026年のDjangoセキュリティリリースによると、大文字小文字混在のCache-Control: privateを持つレスポンスが誤ってキャッシュされ、Authorizationヘッダーを持つリクエストへのレスポンスが共有キャッシュに保存される可能性がありました。
Django 5.1で導入されたLoginRequiredMiddlewareは、サイト全体で認証を強制します:
# settings.py
MIDDLEWARE = [
# ... other middleware
"django.contrib.auth.middleware.LoginRequiredMiddleware",
]
# Exempt specific views
from django.contrib.auth.decorators import login_not_required
@login_not_required
def public_view(request):
return HttpResponse("Public content")これは保護されたビューに@login_requiredをデコレートする従来のパターンを逆転させます。ほとんどのビューで認証が必要なアプリケーションでは、ボイラープレートを削減し、保護されたエンドポイントの意図しない公開を防ぎます。
MiddlewareMixinとレガシーミドルウェアからの移行
MiddlewareMixinは、旧スタイルのミドルウェア(process_requestとprocess_responseメソッドを使用)を新しい呼び出し可能パターンに橋渡しします。django.utils.deprecation.MiddlewareMixinは非推奨であり、Django 6.2で削除される予定です。代わりにdjango.middleware.MiddlewareMixinを使用してください。
# middleware/legacy_style.py
from django.middleware import MiddlewareMixin
class LegacyStyleMiddleware(MiddlewareMixin):
"""Middleware using the legacy hook-based pattern."""
def process_request(self, request):
# Called before view, return None to continue
request.custom_attribute = "value"
return None
def process_response(self, request, response):
# Called after view, must return response
response["X-Custom-Header"] = "middleware-added"
return response新しいミドルウェアではMiddlewareMixinを避けてください。呼び出し可能パターンはより明確な制御フローを提供し、非同期Djangoとの互換性も向上します。
Django ミドルウェアの面接でよく聞かれる質問
技術面接では、Djangoのリクエストライフサイクルの理解を評価するためにミドルウェアの質問がよく含まれます。これらの質問はシニアDjango開発者の面接で頻繁に登場します。
Q: ミドルウェアの順序とレスポンスの実行順序の違いは何ですか?
ミドルウェアはMIDDLEWAREを通じてリクエストを上から下へ処理しますが、レスポンスは下から上へ処理します。玉ねぎのように考えてください:最も外側のミドルウェアがリクエストを最初に見て、レスポンスを最後に見ます。
Q: ミドルウェアのショートサーキットはどのように機能しますか?
ミドルウェアがget_response()を呼び出す代わりにHttpResponseを返すと、リクエストは内側のミドルウェアやビューに到達しません。レスポンスは戻る途中ですべての外側のミドルウェアを通過します。この動作は、すべてのprocess_responseメソッドがショートサーキットに関係なく実行される旧来のMIDDLEWARE_CLASSES設定とは異なります。
Q: ミドルウェアでrequest.userにアクセスすべきタイミングは?
AuthenticationMiddlewareが実行された後のみです。認証ミドルウェアがアタッチする前にrequest.userにアクセスするとAttributeErrorが発生します。ユーザー情報が必要なカスタムミドルウェアは、MIDDLEWAREリストでAuthenticationMiddlewareの後に配置してください。
Q: ミドルウェアを非同期互換にするにはどうすればよいですか?
ミドルウェアクラスにasync_capable = Trueを設定し、await get_response(request)を使用して__call__を非同期メソッドとして実装します。同期と非同期の両方のコンテキストで動作する必要があるミドルウェアには、@sync_and_async_middlewareを使用し、iscoroutinefunction(get_response)をチェックして適切に分岐します。
今すぐ練習を始めましょう!
面接シミュレーターと技術テストで知識をテストしましょう。
本番環境と面接に向けたDjangoミドルウェアのマスター
Djangoミドルウェアは、リクエストライフサイクル全体にまたがる横断的関心事を制御します。Django 6.0でミドルウェアを扱う際の重要なポイントは以下の通りです:
- ミドルウェアはオニオンパターンで実行される:リクエストは上から下へ、レスポンスは下から上へ流れる
- ASGIデプロイメントでは
async_capable = Trueを設定してスレッドプールのオーバーヘッドを回避する process_viewは実行前のビューメタデータ検査に、process_exceptionは一元化されたエラーロギングに使用する- リクエストIDミドルウェアは分散サービス間のログ相関を可能にし、本番環境での一般的な要件である
LoginRequiredMiddlewareは認証パターンを逆転させる:ビューはデフォルトで保護され、公開ビューは明示的に除外される- 非推奨の
django.utils.deprecation.MiddlewareMixinはDjango 6.2でdjango.middleware.MiddlewareMixinに移行される - ミドルウェアの順序は、どのコンポーネントが
request.user、セッションデータ、その他のリクエスト属性を見るかを決定する
Django ORMとREST frameworkパターンのより詳細な解説については、Django ORMクエリ最適化ガイドを参照してください。
Django のバグを見つけられますか
実際のコード、隠れたバグ、1日1回。アカウントなしで試せます。

執筆
Anthony Fillion-MailletSharpSkill 創業者
10 年以上フルスタック開発に携わっています。SharpSkill を運営し、ここで公開される内容に責任を負っています。
2026年9月18日 更新
タグ
共有
関連記事

Django 5.2 カスタムミドルウェアとシグナル処理:技術面接で差をつける実践ガイド
Django 5.2のカスタムミドルウェアとシグナル処理を技術面接の観点から徹底解説。非同期ミドルウェア、カスタムシグナル、実装パターンを網羅した実践ガイドです。

Django面接対策:ORM、ミドルウェア、DRFの実践的な質問と回答
Django面接で頻出するORM最適化(select_relatedとprefetch_related、Django 6.1のFETCH_PEERSモード)、ミドルウェアアーキテクチャ、Django REST Frameworkのシリアライザパフォーマンス、パーミッション、ページネーションパターンを解説します。

Django SignalsとCelery Tasks 2026年版: 適切な使い分けと面接対策ガイド
Django SignalsとCeleryタスクの違いを徹底解説。同期処理と非同期処理の使い分け、パフォーマンス最適化、面接でよく聞かれる質問と回答例を網羅的に紹介します。