Per-host callbacks

Parsing the host from request.get_host() and lookup its corresponding object instance (e.g. site) in every view violates DRY. If these dynamic hosts had a lot of views this would become particularly unwieldy.

To remedy this, you can optionally specify a callback method to be called if your host matches.

Simply define a callback function:

from django.shortcuts import get_object_or_404
from django.contrib.auth.models import User

def custom_fn(request, username):
    request.viewing_user = get_object_or_404(User, username=username)

..and pass it as the callback paramter to the host object:

from django.conf import settings
from django_hosts import patterns, host

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'),
)

This example avoids the duplicated work in every view by attaching a viewing_user instance to the request object. Views referenced by the “dynamic” URLconf can now assume that this object exists.

The custom method is called with the request object and any named captured arguments, similar to regular Django url processing.

Callbacks may return either None or an HttpResponse object.

  • If it returns None, the request continues to be processed and the appropriate view is eventually called.
  • If a callback returns an HttpResponse object, that HttpResponse is returned to the client without any further processing.

Note

There are a few things to keep in mind when using the callbacks:

  • Callbacks are executed with the URLconf set to the second argument in the host_patterns list. For example, in the example above, the callback will be executed with the URLconf as path.to.custom_urls and not the default URLconf.
  • This can cause problems when reversing URLs within your callback as they may not be “visible” to django.core.urlresolvers.reverse() as they are specified in (eg.) the default URLconf.
  • To remedy this, specify the urlconf parameter when calling reverse().
  • When using dynamic hosts based on user input, ensure users cannot specify names that conflict with static subdomains such as “www” or their subdomain will not be accessible.
  • Don’t forget to add handler404 and handler500 entries for your custom URLconfs.

Included callbacks

django-hosts includes the following callbacks:

django_hosts.callbacks.host_site(request, *args, **kwargs)

A callback function which uses the django.contrib.sites contrib app included in Django to match a host to a Site instance, setting a request.site attribute on success.

Parameters:
  • request – the request object passed from the middleware
  • *args – the parameters as matched by the host patterns
  • **kwargs – the keyed parameters as matched by the host patterns

It’s important to note that this uses reverse_host() behind the scenes to reverse the host with the given arguments and keyed arguments to enable a flexible configuration of what will be used to retrieve the Site instance – in the end the callback will use a domain__iexact lookup to get it.

For example, imagine a host conf with a username parameter:

from django.conf import settings
from django_hosts import patterns, host

settings.PARENT_HOST = 'example.com'

host_patterns = patterns('',
    host(r'www', settings.ROOT_URLCONF, name='www'),
    host(r'(?P<username>\w+)', 'path.to.custom_urls',
         callback='django_hosts.callbacks.host_site',
         name='user-sites'),
)

When requesting this website with the host jezdez.example.com, the callback will act as if you’d do:

request.site = Site.objects.get(domain__iexact='jezdez.example.com')

..since the result of calling reverse_host() with the username 'jezdez' is 'jezdez.example.com'.

Later, in your views, you can nicely refer to the current site as request.site for further site-specific functionality.

django_hosts.callbacks.cached_host_site(request, *args, **kwargs)

A callback function similar to host_site() which caches the resulting Site instance in the default cache backend for the time specfified as HOST_SITE_TIMEOUT.

Parameters:
  • request – the request object passed from the middleware
  • *args – the parameters as matched by the host patterns
  • **kwargs – the keyed parameters as matched by the host patterns