django-hosts Documentation

repository·master·Indexed 22 days ago

https://github.com/jazzband/django-hosts

A Django application that routes requests for specific hosts to different URL schemes defined in hostconf modules. It enables serving different content, such as APIs or beta sites, based on the subdomain used. Features include host-aware URL reversing via the host_url template tag and django_hosts.resolvers.reverse, support for dynamic hosts with callbacks, and built-in integration for django.contrib.sites.

Tokens
3.7K
Snippets
14
Records
19
Agent score
76%

What's inside django-hosts

  1. Override the default Django `url` template tag

    master

    If you want to avoid adding {% load hosts %} to every template, you can globally override Django's built-in url tag. This is particularly useful for ensuring compatibility with 3rd party apps that use the standard url tag but need to respect your host configurations.

    To do this, add 'django_hosts.templatetags.hosts_override' to your TEMPLATES configuration under OPTIONS['builtins'].

    # settings.py
    TEMPLATES = [
        {
            'BACKEND': 'django.template.backends.django.DjangoTemplates',
            'OPTIONS': {
                'builtins': [
                    'django_hosts.templatetags.hosts_override',
                ],
            },
        },
    ]
  2. Configure django-hosts to work with Django Debug Toolbar

    master

    To use django-hosts alongside Django Debug Toolbar, you must ensure the middleware order is correct. The debug_toolbar.middleware.DebugToolbarMiddleware must be placed after django_hosts.middleware.HostsRequestMiddleware and before django_hosts.middleware.HostsResponseMiddleware in your MIDDLEWARE setting. Additionally, you must be using django-debug-toolbar version 0.9.X or higher.

    MIDDLEWARE = [
        "django_hosts.middleware.HostsRequestMiddleware",
        # your other middlewares..
        "debug_toolbar.middleware.DebugToolbarMiddleware",
        "django_hosts.middleware.HostsResponseMiddleware",
    ]
  3. Use callbacks in host definitions to avoid repetitive logic

    master

    To avoid repeating host-lookup logic (like fetching a Site or User object) in every view, you can define a callback function and pass it to the host() object via the callback parameter.

    When a host matches, the callback is executed with the request object and any named arguments captured from the host regex.

    Behavior based on return value:

    • If the callback returns None, processing continues and the view associated with the host's URLconf is called.
    • If the callback returns a django.http.HttpResponse object, that response is returned immediately to the client, bypassing the view.

    Important Considerations:

    • URLconf Context: Callbacks are executed within the context of the specific URLconf assigned to that host. This means django.urls.reverse might not find URLs defined in your default URLconf unless you explicitly provide the urlconf parameter.
    • Subdomain Conflicts: If using dynamic hosts (e.g., (?P<username>\w+)), ensure users cannot register names that conflict with static subdomains like www.
    • Error Handlers: Remember to add handler404 and handler500 entries for any custom URLconfs you define.
    from django.shortcuts import get_object_or_404
    from django.contrib.auth.models import User
    from django.conf import settings
    from django_hosts import patterns, host
    
    # 1. Define the callback function
    def custom_fn(request, username):
        # Attach data to the request for use in views
        request.viewing_user = get_object_or_404(User, username=username)
    
    # 2. Pass the callback path to the host() function
    host_patterns = patterns(
        "",
        host(r"www", settings.ROOT_URLCONF, name="www"),
        host(
            r"(?P<username>\w+)",
            "path.to.custom_urls",
            callback="path.to.custom_fn",
            name="with-callback",
        ),
    )
  4. Define host patterns using patterns() and host()

    master

    To route requests to different URL configurations based on the hostname, define host_patterns in a dedicated module. Use patterns() to group host definitions and host() to define specific host matching rules using regular expressions.

    Important: Patterns are matched in order. Place more specific patterns (like www) before more general/wildcard patterns (like \w+) to prevent incorrect routing.

    from django.conf import settings
    from django_hosts import patterns, host
    
    host_patterns = patterns(
        "",
        host(r"www", settings.ROOT_URLCONF, name="www"),
        host(r"(\w+)", "path.to.custom_urls", name="wildcard"),
    )
  5. Define host patterns in a hostconf module

    master

    Create a module (e.g., hosts.py) to define how different hosts map to specific URLconf modules. Use patterns() to group host definitions and host() to define individual host mappings.

    Key Rules:

    • Patterns are evaluated in order.
    • The first argument to host() is a regular expression matched against the extreme left of the requested host.
    • It is implied that all patterns end with either a literal full stop (.) or an end-of-line metacharacter.
    • If no pattern matches, the request falls back to the standard ROOT_URLCONF.
    from django_hosts import patterns, host
    
    host_patterns = patterns(
        "path.to",
        host(r"api", "api.urls", name="api"),
        host(r"beta", "beta.urls", name="beta"),
    )
  6. Configure django-hosts in Django settings

    master

    To integrate django-hosts into your Django project, follow these steps in your settings.py:

    1. Add 'django_hosts' to your INSTALLED_APPS.
    2. Add 'django_hosts.middleware.HostsRequestMiddleware' to the beginning of your MIDDLEWARE list.
    3. Add 'django_hosts.middleware.HostsResponseMiddleware' to the end of your MIDDLEWARE list.
    4. Define ROOT_HOSTCONF with the dotted Python import path to your host configuration module (e.g., mysite.hosts).
    5. Define DEFAULT_HOST with the name of the host pattern you want to use as the default when no other patterns match or no name is provided to the host_url template tag.
    INSTALLED_APPS = [
        # ...
        'django_hosts',
        # ...
    ]
    
    MIDDLEWARE = [
        'django_hosts.middleware.HostsRequestMiddleware',
        # ... other middleware ...
        'django_hosts.middleware.HostsResponseMiddleware',
    ]
    
    ROOT_HOSTCONF = 'mysite.hosts'
    DEFAULT_HOST = 'default'
  7. Configure the default URL scheme with `HOST_SCHEME`

    master

    You can control the default scheme used by the host_url template tag by setting HOST_SCHEME in your Django settings.

    • The default behavior is to use // (protocol-relative).
    • You can change this to a specific scheme like https globally.
    # settings.py
    HOST_SCHEME = 'https'
  8. Configure django-hosts settings

    master

    Add the following settings to your settings.py to configure django-hosts behavior:

    SettingTypeDescription
    ROOT_HOSTCONFRequiredThe dotted Python import path of the module containing your host_patterns (e.g., 'myproject.hosts').
    DEFAULT_HOSTRequiredThe name of the host pattern to use as the default when no host is specified.
    PARENT_DOMAINOptionalThe parent domain name to be appended to the reversed domain when using host_url.
    HOST_SCHEMEOptionalThe scheme to prepend to host names during reversing (e.g., 'https://'). Defaults to '//'.
    HOST_PORTOptionalThe port to append to host names during reversing. Defaults to '' (empty string).
    HOST_SITE_TIMEOUTOptionalCache duration in seconds for cached_host_site callback. Defaults to 3600.
  9. Configure Fully Qualified Domain Names (FQDN) with `PARENT_HOST`

    master

    By default, host_url generates URLs relative to the host pattern. If you want to append a default domain name to all generated URLs, set the PARENT_HOST setting in your Django configuration.

    Example: If PARENT_HOST = "example.com", a host pattern for admin will render as //admin.example.com/... instead of just //admin/....

    # settings.py
    PARENT_HOST = "example.com"
  10. Fix failing pytest tests using client.post() with django-hosts

    master

    If your pytest tests using client.post(...) are failing after adding django-hosts, it is likely because the request is not being associated with the expected host. To fix this, pass the SERVER_NAME argument to the post call to specify the host that should handle the request.

    client.post(..., SERVER_NAME="api-server.something")
  11. Use regular expressions in host patterns

    master

    You can use regular expressions in the host() function to match multiple subdomains to the same URLconf. For example, to route both foo.example.com and bar.example.com to the same URLconf, use a grouping regex.

    from django_hosts import patterns, host
    
    host_patterns = patterns(
        "",
        host(r"(foo|bar)", "path.to.urls", name="foo-or-bar"),
    )