Turn off reversing
Goal
Disable the resolver-acquisition patch and fall back to routing-only, either as a temporary escape hatch (a Django upgrade lands before a compatible django-hostmap release) or as a deliberate, permanent choice for a project that only wants host-based routing.
Prerequisites
- None; this is a single setting.
Steps
1. Set HOSTMAP_PATCH_REVERSE = False
# settings.py
HOSTMAP_PATCH_REVERSE = False
With the patch off:
- Routing keeps working exactly as before.
HostmapMiddlewarestill matches the host, setsrequest.urlconf, populatesrequest.hostmap, and handlesredirect_toentries. None of that depends on the reverse patch. - Stock
reverse()and{% url %}revert to ordinary Django behaviour. Cross-host names that used to come back as absolute URLs now raiseNoReverseMatchif they do not resolve on the active host's URLconf, the same as they would with no hostmap installed at all. - The explicit API keeps working.
hostmap.urls.reverse(),build_absolute_uri(), anduse_host()call the same resolution logic the patch would have used; there are never two implementations to keep in lockstep, so turning off the patch does not touch this code path at all.
2. Know when this happens automatically, versus when you choose it
This is the documented remediation for two situations:
- A Django upgrade breaks the seam. At
AppConfig.ready(), hostmap runs a self-test that reverses a probe pattern through the resolver seam. If Django's internals have moved in a way the seam cannot handle, startup fails withImproperlyConfigurednaming this setting as the fix. This is a deliberate hard failure: better a loud startup error than a subtly broken production deploy. - A newer, not-yet-broken Django version.
hostmap.E009fails startup when the running Django is newer than the package's tested ceiling AND this setting is left on (the default), even if the seam self-test still passes: the patch is running a private resolver seam that has not been verified on that Django version, so this is a hard stop rather than advance notice. SetHOSTMAP_PATCH_REVERSE = Falseto clear it and run routing-only until a compatible release ships; with this setting already off, the same version-ceiling condition is onlyhostmap.W004, a non-blocking Warning, since routing-only never exercises the seam.
3. Migrate existing cross-host links if you turn this off permanently
If you are choosing routing-only deliberately (not as a temporary workaround), audit any template or Python code relying on the old cross-host absolute URLs and switch those specific call sites to the explicit API:
from hostmap.urls import build_absolute_uri
build_absolute_uri("api:user-detail", args=[7])
This still gives you an absolute, cross-host URL where you need one; only
the automatic behaviour of stock reverse() is gone.
Verify it worked
import pytest
from django.urls import NoReverseMatch, reverse
@pytest.mark.django_db
def test_stock_reverse_no_longer_crosses_hosts(settings):
settings.HOSTMAP_PATCH_REVERSE = False
with pytest.raises(NoReverseMatch):
reverse("api:user-detail", args=[7]) # assuming this only exists on "api"
@pytest.mark.django_db
def test_routing_still_works(client, settings):
settings.HOSTMAP_PATCH_REVERSE = False
response = client.get("/users/7/", SERVER_NAME="api.example.com")
assert response.status_code == 200
def test_explicit_api_still_works(settings):
settings.HOSTMAP_PATCH_REVERSE = False
from hostmap.urls import build_absolute_uri
assert build_absolute_uri("api:user-detail", args=[7]).startswith("https://api.")
Note that HOSTMAP_PATCH_REVERSE is read once at AppConfig.ready() to
decide whether to install the seam; flipping it via settings in a live test
process does not retroactively install or remove the patch. Override it in
your settings module before the app starts (or accept that a test flipping
it mid-process is exercising the explicit API's independence from the patch,
not a live toggle of the patch itself).
Common pitfalls
- Expecting flipping the setting at runtime to install or remove the
patch. The patch is installed once, at
AppConfig.ready(). Change this setting in your settings module before the process starts, not by mutatingsettingsmid-run and expecting the seam to appear or disappear. - Assuming routing also breaks. It does not; only reversing is affected. This is the whole point of the escape hatch: a broken seam should degrade to "cross-host links are relative-only", never to "the site is down".
- Assuming
hostmap.E009/hostmap.W004are interchangeable. They are the same underlying condition (Django newer than the tested ceiling) at two different severities depending onHOSTMAP_PATCH_REVERSE:hostmap.E009(patch active) fails startup and must be addressed before the process comes up;hostmap.W004(patch off) is advance warning, a prompt to test the upgrade in a branch before re-enabling the patch, per the operational notes in the troubleshooting guide.
Related
- How host-aware reversing works: why the seam exists and what the self-test protects against.
- Reverse out of a request: the explicit API that keeps working regardless of this setting.
- Settings reference:
HOSTMAP_PATCH_REVERSEand thehostmap.E009/hostmap.W004checks.