在Django中使用二級域名

發佈於2012年2月24日 -

最近一直在用Django寫東西,感覺非常棒,開發效率非常高,系統本身也很靈活。但是這樣一個強大的框架也並非完美,目前,Django還不支持域名的處理,URL的路由並不考慮host信息,因此對於曬課廳這樣的項目,如果想使用二級域名作爲學校的區分,就顯得有些困難。

於是我們有必要想個辦法解決這個問題。一個比較方便的做法是,使用middleware對URL做一些修改,通過一點技巧來讓URL的路由「識別」二級域名。不難想到這樣處理:

假設我們有兩個二級域名需要放在一個Django項目裏,分別是:www.shaiketing.com和thu.shaiketing.com,那麼爲了使用URL的路由,我們需要讓路由系統知道我們訪問的是www和thu,而路由系統並不關心host信息,所以我們只要讓路由系統看到/www/和/thu/就好。因此,我們實際上是把這兩個URL變成了www.shaiketing.com/www/和thu.shaiketing.com/thu/,這樣路由系統就知道我們訪問的是什麼二級域名了。

具體怎麼做呢?寫一個middleware:

from django.http import HttpResponsePermanentRedirect

class SubdomainMiddleware(object):
    def process_request(self, request):
        domain_parts = request.get_host().split('.')
        if len(domain_parts) == 3:
            request.path_info = '/%s%s' % (domain_parts[0], request.path)
        else:
            return HttpResponsePermanentRedirect('http://www.shaiketing.com')
        return None

通過這樣的middleware,我們就可以將二級域名附加到URL路由用到的request.path_info裏了。

然而,這樣做還會有點問題,reverse的時候並沒有host信息,所以我們還需要對reverse做一下處理:

from django.conf import settings

from django.core import urlresolvers
def reverse_subdomain(*args, **kwargs):
    path_info = old_reverse(*args, **kwargs)
    parts = path_info[1:].split('/', 1)
    path_info = 'http://%s%s/%s' % (
            parts[0], settings.SESSION_COOKIE_DOMAIN, parts[1])
    return path_info
old_reverse = urlresolvers.reverse
urlresolvers.reverse = reverse_subdomain

一定要把這段代碼加在某個models.py裏,加在其他位置都不合適(可以想想爲什麼?)

現在這個問題應該比較完美的解決了。最後附上urls.py:

from django.conf.urls.defaults import patterns, include, url

urlpatterns = patterns('',
    url(r'^www/', include('www.urls')),
    url(r'^thu/', include('thu.urls')),
)