views:

1352

answers:

4

I'm starting a new web app project using Django and Pinax. I want to be able to give my users unique domain names like Wordpress and other sites do : username.wordpress.com. I'm not sure how to approach this with Django, since the url parsing logic (in urls.py) starts with the url AFTER the domain name.

More specifically, there will be multiple groups of users, each group having a unique name. Not sure that makes a difference, but I thought I should mention that.

Is there some way I can manipulate the http request so that the URL looks to Django as if the url were something like www.domain.com/groupname, but still showed in the browser address bar as groupname.domain.com?

+2  A: 

You need to handle this via your webserver. If you have Django urls like...

/users/<username>/

... then use rewrite rules in the webserver to map <username>.domain.com to domain.com/users/<username>/.

If you're using Apache, you can read up here. Otherwise, each webserver has their own conventions but all will support the notion of url rewrites.

Daniel
This sounds like it would work, and there is even an example 'Virtual Hosts' that is pretty similar to what I want. But I in no way resemble an Apache admin, and am scared of putting 'application logic' in the web server config. Also I'd have to develop on Apache instead of the Django dev server.
Chris Lawlor
You can still develop on the dev server... just don't point to absolute URLs in your templates. I also hate putzing with Apache conf files, but it's a copy and paste job.
Daniel
+15  A: 

You can use some custom middleware to intercept the request and get the subdomain from it. The following code will retrieve the subdomain and redirect to a view by reversing the named url.

Put it in a middleware.py file in your app.

Make sure you set up the middleware in your settings.py file.

Make sure you've named your view in urls.py

middleware.py

from django.http import HttpResponseRedirect
from django.core.urlresolvers import reverse
import re

subdomain_pattern = re.compile('(?P<subdomain>.*?)\..*?')

class SubdomainMiddleware(object):
    def process_request(self, request):
        match = subdomain_pattern.match(request.get_host())
        subdomain = match.group('subdomain')
        redirect_url = reverse('groups_detail', args=[subdomain])
        return HttpResponseRedirect(redirect_url)

urls.py

from django.conf.urls.defaults import *

urlpatterns = patterns('',
    url(r'^groups/(?P<name>.+)/$', 'groups.views.detail', {}, name='group_detail'),
)

Note: this code is untested.

Redirecting can alter the URL's appearance. If you want to avoid this, simply call the associated view, capture its result, and return it in an HttpResponse().

Soviut
+1: Middleware is the best way to do it, imho. On the webserver/dns side, check for wildcard subdomains.
Tiago
This sounds good. Not entirely sure how to to change the path of the request - does HttpRequest.build_absolute_uri(location) actually change the path, or just return a string? I could change the 'path` attribute directly, but docs say "all attributes except `session` should be considered read only.
Chris Lawlor
Finding the subdomain is just part of the mix. If this works it sounds like a great solution I haven't heard of, but could you update the post with the code to change the request url so it reflects the "real" Django url? thanks (I have a site with rewrites and I like this possibility much better).
Daniel
I greatly modified my code to do response redirects. Its untested, but should give you a good starting point.
Soviut
Also, the reverse() isn't totally necessary, you could hard code the url in the response itself. But reverse urls means the url pattern can change and the middleware will still work.
Soviut
Assuming the redirect doesn't incur too much overhead, I think this will do exactly what I need. Thank you!!!
Chris Lawlor
Also note that its possible to do non-django middleware in the form of WSGI Middleware on the webserver. You can essentially do the exact same thing, but you may not be able to reverse your urls. Instead you'll need to make it hard coded in your web server settings.
Soviut
hmmm.... a redirect is going to change the url as it appears to the user.
Daniel
@Daniel see my note i added to the end for a possible way to solve this.
Soviut
I like this idea in general, but it doesn't seem like a comprehensive way to solve the problem... it bypasses the django url dispatcher and basically re-implements it in middleware. Plus, there could be other middleware classes that behave differently depending on url of the request. (continued)
Daniel
... a complete solution should hook in at a lower level
Daniel
Now that I think about it, that "lower level" might be a custom url dispatcher (or monkeypatched version of the existing one)
Daniel
This doesn't bypass the url dispatcher, it works along side it. The url dispatcher simply doesn't pay attention to subdomains, those aren't part of the 'pretty url'. hooking it in with middleware is very elegant since the middleware can be part of the actual "groups" app you're using.
Soviut
In this system you'll be mapping more than one subdomain url to view functions. It's unavoidable that you'll need to recognize each url and call the appropriate view function, unless you hook into the url dispatcher directly... which begs the question, why not do it in the dispatcher to begin with?
Daniel
In that case, use the subdomain to fetch the user id and store it in the session. We've done that with a school's website that had more than one campus. Each campus was a subdomain that we'd throw into the session and check in our views.
Soviut
Exactly what @Tiago said.
Ryan Duffield
Sure, you could store the subdomain in the session or in the request, if you so chose. But then you're offloading the behavior to the view functions and/or templates. A custom dispatcher would avoid that by directly mapping a url to a view in urls.py, in the same way an Apache rewrite rule does.
Daniel
A: 

See this other alternative configuring the appserver

panchicore
A: 

http://github.com/tkaemming/django-subdomains

Daryl
thanks for posting - I'll definitely check this out next time I need this (project that this question was related to got dropped).
Chris Lawlor