ICVOSS DJANGO PACKAGE REGISTRY

The package index django-hostmap Add a redirect host

Add a redirect host

Documentation

Goal

Redirect one host to another, preserving the full path and query string: the classic case is redirecting the bare apex domain (example.com) to www.example.com.

Prerequisites

Steps

1. Add a redirect_to entry

A redirect entry sets redirect_to instead of urlconf. It names the label of a non-redirect entry (hostmap.E003 fails startup if an entry has both or neither of urlconf / redirect_to).

# settings.py
HOSTMAP = {
    "www": {"subdomain": "www", "urlconf": "config.urls.www"},
    "apex": {"host": "example.com", "redirect_to": "www"},
}
HOSTMAP_PARENT_DOMAIN = "example.com"
HOSTMAP_DEFAULT = "www"

apex here is a host entry (the bare parent domain), not a subdomain entry, since it has no subdomain label of its own.

2. Choose permanent or temporary redirects

HOSTMAP_REDIRECT_PERMANENT (default True) controls the status code for every redirect entry:

HOSTMAP_REDIRECT_PERMANENT = True   # 301, the default: browsers and
                                     # search engines cache this
HOSTMAP_REDIRECT_PERMANENT = False  # 302, useful while you are still
                                     # deciding the final host

This is a single project-wide setting, not per-entry: every redirect entry in the map uses the same status code.

3. Confirm redirect targets cannot chain

redirect_to must name a non-redirect entry. Redirecting one redirect entry to another fails startup as hostmap.E004, because chained redirects are never useful and hostmap refuses to let them accumulate silently.

# This fails hostmap.E004: "apex2" points at "apex", which is itself a
# redirect entry.
HOSTMAP = {
    "www": {"subdomain": "www", "urlconf": "config.urls.www"},
    "apex": {"host": "example.com", "redirect_to": "www"},
    "apex2": {"host": "old.example.com", "redirect_to": "apex"},  # E004
}

Point apex2 at www directly instead.

Verify it worked

curl -i http://example.com/blog/?ref=newsletter

You should see:

HTTP/1.1 301 Moved Permanently
Location: https://www.example.com/blog/?ref=newsletter

Both the path (/blog/) and the query string (?ref=newsletter) are preserved; only the host changes.

import pytest


@pytest.mark.django_db
def test_apex_redirects_to_www(client):
    response = client.get("/blog/?ref=newsletter", HTTP_HOST="example.com")
    assert response.status_code == 301
    assert response["Location"] == "https://www.example.com/blog/?ref=newsletter"

Common pitfalls