Django domain redirect middleware

Most web developers know it’s possible to serve one site on several domains or subdomains, using eg. the ServerAlias Apache directive. Sometimes this behaviour is not wanted: you want your main domain to be “foo.tld”, although “www.foo.tld” should work too, and maybe even some completely different domains.

This way it’s possible to have permalinks, and you won’t get bad points from search engine spiders who don’t like the same content to be available on several URIs.

In Django there’s the PREPEND_WWW setting, which will force all requests to be redirected to www.foo.bar when coming in on foo.bar, etc. This functionality is rather limited though. As I wanted to be able to have one unique main domain in my new application, I wrote a middleware which accomplishes this in a very generic way, using the django.contrib.sites framework. You need to add this middleware before all others in your settings file, even before the CommonMiddleware.

Here’s the code:

from django.contrib.sites.models import Site
from django.http import HttpResponsePermanentRedirect
from django.core.urlresolvers import resolve
from django.core import urlresolvers
from django.utils.http import urlquote

class DomainRedirectMiddleware(object):
    def process_request(self, request):
        host = request.get_host()
        site = Site.objects.get_current()

        if host == site.domain:
            return None

        # Only redirect if the request is a valid path
        try:
            # One issue here: won't work when using django.contrib.flatpages
            # TODO: Make this work with flatpages :-)
            resolve(request.path)
        except urlresolvers.Resolver404:
            return None

        new_uri = '%s://%s%s%s' % (
                request.is_secure() and 'https' or 'http',
                site.domain,
                urlquote(request.path),
                (request.method == 'GET' and len(request.GET) > 0) and '?%s' % request.GET.urlencode() or ''
            )

        return HttpResponsePermanentRedirect(new_uri)

Make sure you got the sites framework set up correctly when using this! As noted in the code, this doesn’t work with the Flatpages framework yet, this is TODO.

2 Responses to “Django domain redirect middleware”

  1. Vincent van Adrighem said on

    Why not use virtual hosts with rewriterules?
    If you’re using apache anyway, then this is the most elegant solution IMHO.
    You want every request to go to http://www.somesite.net, but used to have http://www.oldsite.org, then set up a virtual host on http://www.oldsite.org containing nothing but a rewriterule:

    RewriteEngine On
    RewriteRule ^(.*)$ http://www.somesite.net/1 [R=permanent]

    That way, client software even gets a 301 signal, giving the browser the possibility to automatically update your bookmarks.

  2. Nicolas said on

    Vincent: my solution also uses a HTTP 301 (a HttpResponsePermanentRedirect also translates to a HTTP 301 reply). One of the main benefits is it doesn’t force you to use multiple vhosts, which is not always possible in shared hosting environments.

    By the way, your solution could be simplified by using something like

    Redirect permanent / http://foo.bar/

    in your Apache configuration, instead of pulling in mod_rewrite ;-)

Leave a comment