Running Mango alongside other Django apps on different subdomains

Over on MTG apps I'm using Dave Fowler's subdomains middleware to run a Mango blog and another Django app on different subdomains.

Getting this up and running locally was a piece of cake but mirroring the setup on my WebFaction slice proved to be more challenging. The quick fix would have been to create two separate Django projects; one for each app. This would have resulted in unnecessary duplication of shared settings, though, so I was thrilled to find a workable solution in the end.

Here's the project-level urls.py:

from django.conf.urls.defaults import *
from django.core.urlresolvers import resolve

import app1.urls
import app2.urls

def route_request(request):
    urlconf = app2.urls if request.subdomain == 'app2' else app1.urls
    view, args, kwargs = resolve(request.path, urlconf=urlconf)
    return view(request, *args, **kwargs)

urlpatterns = patterns('',
    (r'', lambda request: route_request(request)),

    # associate urlconfs with their respective apps
    (r'', include(app1.urls, app_name='app1')),
    (r'', include(app2.urls, app_name='app2')),
)

It's worth noting that I'm including the urlconfs explicitly even though the requests are all handled by route_request. Django's URL resolver relies on urlconfs and apps being associated in this way. Without this information the url template tag throws horrible NoReverseMatch exceptions.

This setup — without violating DRY — appeared to be getting the job done, but today I noticed that it had broken Django's automatic slash appending. Thankfully, it's possible to add this functionality manually without messing with Mango's source, by taking advantage of the fact that Mango's default URL resolution can be overridden.

# mango/urls/custom.py

from django.conf.urls.defaults import *
from django.core.urlresolvers import reverse
from django.http import HttpResponsePermanentRedirect

from mango.handlers import moderate
from mango.views import archives, search

urlpatterns = patterns('',
    (r'^archive$', lambda request: HttpResponsePermanentRedirect(reverse(archives))),
    (r'^moderate/(approve|delete|spam|close)$', moderate),
    (r'^search$', search),
    (r'^.*[^/]$', lambda request: HttpResponsePermanentRedirect('%s/' % request.path)),
)

The fourth tuple is responsible for appending slashes. The preceding patterns act as guards to ensure that slashes are not appended inappropriately. (Mango is extremely lenient as far as the archives page is concerned – "archive", "archive/", and "archives" will all take you to "archives/".)