Premier League Predictor: Django & MySQL — Chapter 12, Exercise 2 ==================================================== TASK Explain why the same FORCE_SCRIPT_NAME setting that fixes every link the Django admin generates has no effect at all on season_default_gameweek's own redirect() call, tracing the distinction back to reverse()-built paths versus a raw hardcoded string. SOLUTION FORCE_SCRIPT_NAME works by changing what Django's own URL-generation machinery — specifically reverse(), and everything built on top of it like the {% url %} template tag — treats as the application's real root when it assembles a path. When some code calls reverse('some-view-name') (or the admin calls the equivalent internally to build a link to a changelist or a save-and-continue redirect), Django looks up that view's URL pattern and constructs the resulting path fresh, at that moment, using whatever SCRIPT_NAME/FORCE_SCRIPT_NAME is currently configured. The admin uses exactly this reverse()-based path construction throughout its own internals — every link, redirect, and "view on site" URL it renders is built this way — so every one of those paths automatically picks up the FORCE_SCRIPT_NAME prefix the moment the setting is added, with zero code changes needed anywhere in the admin itself. season_default_gameweek's own redirect() call is built completely differently: return redirect(f'/gameweeks/{first_gameweek.id}/fixtures/') constructs a plain Python string directly, using an f-string, with no call to reverse() or any other Django URL-resolution function anywhere in that line. redirect() itself, when handed a string that already looks like a URL (starting with a slash), doesn't try to interpret it as a view name to resolve — it just wraps that exact string, as written, in an HttpResponseRedirect. There is no reverse() call in this code path for FORCE_SCRIPT_NAME to intercept or influence at all — the string is already fully formed by the time redirect() ever sees it. The distinction, precisely: FORCE_SCRIPT_NAME can only affect a path at the moment Django itself is actively constructing that path via its own resolution machinery. A path that was never constructed that way — because a developer wrote out the literal characters by hand instead — has already left that machinery's reach before FORCE_SCRIPT_NAME could ever have a chance to apply to it. WHY THIS WORKS AS AN ANSWER ---------------------------- It explains precisely what FORCE_SCRIPT_NAME actually hooks into (Django's own URL-generation functions, specifically reverse() and what's built on it), confirms the admin genuinely uses that mechanism throughout, and contrasts it against season_default_gameweek's own literal f-string construction, which never calls into that machinery at all and so is structurally outside FORCE_SCRIPT_NAME's reach.