7
votes

I have a Django app that currently supports multiple languages. I'd like to add subdomain support so that going to 'de.mysite.com' queries articles in German, while 'mysite.com' queries things in English (the default language). There will be about 20 subdomains all pointing to the same Django app.

I have an abstract model with all of the fields for my data and a derived model for each language. Each language has its own database table, like so:

class ArticleBase(models.Model):
    title = models.CharField(max_length=240, unique=True)
    date_added = models.DateField(auto_now_add=True)

    class Meta:
        abstract = True

# This is English, the default.
class Article(ArticleBase):
    pass

class Article_de(ArticleBase):
    pass

I can get articles like this (I have this working today):

def article(request, title, language=None):
    if language:
        mod = get_model('app', 'Article_' + language)
        items = mod.filter(title=title)
    else:
        items = Article.objects.filter(title=title)

This is my current URL pattern:

url(r'^article/(?P<title>[a-zA-Z_-]+)/$", 'app.views.article', name='article'),

How can I parse the subdomain prefix in a URL pattern so it can be passed into the article view? Or should I be getting this info from the request when I'm processing the view?

3

3 Answers

10
votes

The URLS in django don't have access to the domain section of the URL, so that is not an option. Doing it manually in each view is doable but not so easy to maintain.

I think that a custom middleware solution is probably better where you check the request headers in the middleware and then load the appropriate language (or you replace the accept-language headers and let django do it's magic)

The localemiddleware can make the language available which you can then easily use to pass through to the models/queries as needed.

Also if I may ask: why store every entry in a separate table/model? Can't you just add a language field to the model and store everything in one table? Because going for 20 or so models for articles can become harder to maintain than just 1 model.

UPDATE:

I've played around a little bit and the middleware required is quite simple (although my testing was quite limited):

class SubDomainLanguage(object):
    def process_request(self, request):
        try:
            request.session['django_language'] = request.META['HTTP_HOST'].split('.')[0]
        except KeyError:
            pass

is the middleware and then change the settings to include the following:

MIDDLEWARE_CLASSES = (
    ...
    'django.contrib.sessions.middleware.SessionMiddleware',
    'subdomainmiddleware.SubDomainLanguage',
    'django.middleware.locale.LocaleMiddleware',
    ...
)

This way you can then leverage the normal Django builtin i18n support.

In the views the language is then available in request.LANGUAGE_CODE

0
votes

I have a case that I have subdomains with periods such as 1.2.3.mydomain.net. I know my domain and set it in my local_settings.py as:

DOMAIN = 'EXAMPLE.net'
TEST_SUBDOMAINS = ["127.0.0.1", "localhost", "testserver"]

I then check that I don't do anything if its for test purposes. After that I get my sub domain as follows:

if (DOMAIN in TEST_SUBDOMAINS):
    return HttpResponse("test only")
subdomain = request.META['HTTP_HOST'].replace((DOMAIN), "")[:-1] 
# -1 is to remove the trailing "." from the subdomain
if subdomain and subdomain != "www" :
# whatever you need...
0
votes

You can just use this easy to use django-subdomains library. It also support subdomain-based URL routing and reversing.