views:

45

answers:

1

I have a Django application being served of (say) example.com. It contains a number of sub-applications (say) strength, speed and skill. The URL scheme is something like http://example.com/strength, http://example.com/speed and http://example.com/skill. This is how I run my dev server (using runserver) and there are no problems whatsoever.

Now, during deployment, I need to have subdomains that map to these sub-applications. More specifically, I want http://x.example.com to map to http://example.com/x (for the above values of x) and then processing can go on.

I googled a little bit and found two ways of doing this.

  • One is to get some middleware to get the subdomain part of the URL and keep it inside the request object passed to my view methods. I then do the whole thing inside my application logic.
  • The other is to use Apache mod_rewrite to do the above URL translation and then let my app run as usual.

I chose the latter since it looked neater and I thought I wouldn't have to include deployment specific code inside my core application.

Now, I'm bitten by a problem which I can't really find a way out of. Inside the skill application, I have a named url skill_home. It's http://example.com/skill. However, once I deploy, the skill_home URL becomes http://skill.example.com/skill. Django appends the /skill to the top level domain and this is what I get. If I do a GET on this URL, mod_rewrite changes it to http://skill.example.com/skill/skill and it doesn't work.

My mod_rewrite snippets look like this

RewriteCond %{HTTP_HOST} !www.example.com$ [NC]
RewriteCond %{HTTP_HOST} ^(www.)?skill.example.com [NC]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule (.*) /skill/$1 

How do I fix this neatly?

+1  A: 

For this answer I'm assuming that you're willing to do a mod_rewrite for each subdomain. I don't think this will work for any subdomain (i.e. the x you mention).

This will strip out the leading /skill/ so that your app will continue to work:

RewriteCond %{HTTP_HOST} !www.example.com$ [NC]
RewriteCond %{HTTP_HOST} ^(www.)?skill.example.com [NC]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule (/skill/)?(.*) /skill/$2

Update

Okay, so you want to strip out the leading part of the URL in the link itself.

Basically, that means you have to write a custom tag to replace the {% url %} tag, something like this:

import re
from django.template import Library
from django.template.defaulttags import URLNode, url

register = Library()

class SubdomainURLNode(URLNode):
    def render(self, context):
        domain = context['request'].get_host()
        subdomain = re.sub(r'^www\.','',domain).split('.')[0]
        path = super(SubdomainURLNode, self).render(context)
        return re.sub(r'^/%s/' % subdomain, '/', path)

@register.tag
def subdomainurl(parser, token, node_cls=SubdomainURLNode):
    """Just like {% url %} but checks for a subdomain."""
    node_instance = url(parser, token)
    return node_cls(view_name=node_instance.view_name,
        args=node_instance.args,
        kwargs=node_instance.kwargs,
        asvar=node_instance.asvar)

I've tested this on my server and it appears to work.

Jordan Reiter
Hmm interesting... I can think of 2 problems. One is what you've already mentioned. I will have a few dynamically created domains. The second is that although the app will work, I'd still see dirty URLs like `http://skill.example.com/skill` when I hover over some links. That's kind of ugly.
Noufal Ibrahim
Hmmm... I must not be understanding how your app is set up. I assumed that /skill/ was the prefix for the skill app. In which case you'd need it right there in the URL in order for it to work.
Jordan Reiter
True. But with a URL like `http://skill.example.com`, the `skill` part is already mentioned. With a dev server running on (say) `127.0.0.1:8080`, I can say `http://127.0.0.1:8080/skill/page1` and it'll work. With the deployed setup, I'd like to say `http://skill.example.com/page1`. This will work fine. However, when I hover over the link for `page1`, I'll see something like `http://skill.example.com/skill/page1` which looks quite ugly.
Noufal Ibrahim
Yeah, the thing is if you are using {% url %} with named URLs, Django is going to use the rules you gave it, so if the path is `/skill/page1` that is what you'll see. I've amended my answer with something I think will work for you.
Jordan Reiter
Let me give it a shot. I'll let you know if it works. Your initial solution worked for me (with the problem of the ugly URLs) and I got tied up with some stuff. I'll post back here once I try. Thanks!
Noufal Ibrahim