from collections.abc import Callable from django.http import HttpRequest, HttpResponse class ScriptPrefixPathMiddleware: """Re-add the ``FORCE_SCRIPT_NAME`` prefix to ``request.path`` under ASGI. Django's ASGI handler sets ``request.path = scope["path"]`` verbatim (see ``django/core/handlers/asgi.py``). When the reverse proxy strips the script-name prefix (e.g. ``/scores``) before forwarding, ``request.path`` — and therefore ``get_full_path()`` — loses the prefix, even though ``reverse()`` still prepends it via the script prefix. The result is the admin login form posting to ``/admin/login/?next=/admin/`` instead of ``/scores/admin/login/?next=/scores/admin/``. URL resolution is unaffected (it uses ``path_info``), so we only need to realign the path-based URLs with the reverse()-based ones. The check is idempotent: if the proxy already forwards the prefix, this is a no-op. """ def __init__(self, get_response: Callable[[HttpRequest], HttpResponse]) -> None: self.get_response = get_response def __call__(self, request: HttpRequest) -> HttpResponse: script_name = request.META.get("SCRIPT_NAME", "").rstrip("/") if script_name and not request.path.startswith(f"{script_name}/"): request.path = f"{script_name}{request.path}" return self.get_response(request)