Using Subdomains with Django

Posted by Ross Poulton on Sat 28 April 2007 #javascript #geeky #programming

As a part of my previously mentioned upcoming bridal gift registry project (which, by the way, performed outstandingly in it's most important private beta ever - my own wedding) I'm giving each user (in this sense, a user is a couple close to getting married) their own subdomain off of the main website - instead of having a URL to their registry like http://yourdomain.com/registries/view/?id=1048 there are beautiful URL's like http://couplesnames.yourdomain.com.

Getting this working was really quite simple, and it's something that I can see being useful for SAAS projects - just take a look at the 37signals projects such as Basecamp and the way they handle per-company logins: each company has it's own subdomain.

The first thing that needs to be done is server configuration. Your domain name needs to have a wildcard entry setup (eg *.yourdomain.com), using Bind9 this is as easy as adding the following line to your domain name config. For other setups, speak to your web hosting provider.

*       CNAME   yourdomain.com.

Next, configure your web server software to answer requests for *.yourdomain.com the same way as www.yourdomain.com. I'm assuming that www.yourdomain.com already works, and that you're using Apache - again, YMMV so speak to your hosting provider. In Apache, just add the following line to your yourdomain.com virtual host configuration:

ServerAlias *.yourdomain.com

After restarting your DNS & web server software, you'll find that going to http://anything.yourdomain.com shows up the same result as http://www.yourdomain.com. Perfect.

Lastly you need to configure Django to treat subdomains differently. In this case I'm making another assumption, that Django is handling requests for yourdomain.com, and that there is a view already in place (eg via urls.py) for handling requests for the root of the domain. I'm also assuming content for your "main page" (eg, anything that's not a subdomain) is handled by other views, and that your main page is under /mypage/.

My 'index' view therefore looks like this:

def index(request):
    django_site = Site.objects.get_current()
    if request.META['HTTP_HOST'] == django_site.domain:
        # The visitor has hit the main webpage, so redirect to /mypage/ 
        return HttpResponseRedirect('/mypage/')

    # Split the domain into it's parts, remove the main part of the domain 
    # from the requested host, and we're left with one variable: 'subdomain'.
    # We also strip out the 'www.' non web-savvy users often type 'www' in 
    # front of every website they visit, so let's not show them an error message!
    domain_parts = django_site.domain.split(".")
    domain = ".".join(domain_parts[1:])
    subdomain = request.META['HTTP_HOST'].replace(domain, '').replace('.', '').replace('www', '')
    # You can now access your data models using 'subdomain', eg:
    couple = Couple.objects.get(subdomain=subdomain)

You can see I'm referring to a model called Couple, with a field named 'Subdomain'. All you need to do is refer to your own model with a 'subdomain' key and you're in business - just remember to enforce unique subdomains at signup time! Lastly, ensure your current Django 'Site' entry (django.contrib.sites) is up to date with the domain set to 'www.yourdomain.com'.

From here you can customise what's shown to the visitor based off of the subdomain they've hit. Very easy to setup, and potentially very powerful - especially in environments where people need something as easy as possible to remember or as unique as possible.