In a django web application, how do you give users their own subdomain?
Asked Answered
W

2

35

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?

Willywilly answered 9/3, 2009 at 2:36 Comment(3)
This is being considered for addition in Django 1.2: code.djangoproject.com/ticket/8896Willywilly
github.com/tkaemming/django-subdomainsDefiniens
thanks for posting - I'll definitely check this out next time I need this (project that this question was related to got dropped).Willywilly
M
24

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().

Machicolate answered 9/3, 2009 at 3:9 Comment(15)
+1: Middleware is the best way to do it, imho. On the webserver/dns side, check for wildcard subdomains.Tichonn
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.Willywilly
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).Emelina
I greatly modified my code to do response redirects. Its untested, but should give you a good starting point.Machicolate
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.Machicolate
Assuming the redirect doesn't incur too much overhead, I think this will do exactly what I need. Thank you!!!Willywilly
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.Machicolate
@Daniel see my note i added to the end for a possible way to solve this.Machicolate
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)Emelina
... a complete solution should hook in at a lower levelEmelina
Now that I think about it, that "lower level" might be a custom url dispatcher (or monkeypatched version of the existing one)Emelina
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.Machicolate
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?Emelina
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.Machicolate
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.Emelina
E
2

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.

Emelina answered 9/3, 2009 at 2:56 Comment(4)
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.Willywilly
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.Emelina
I'm curious. In your opinion do you think this is a better way of doing it than using Middleware? It feels a bit cleaner to me.Nikianikita
It worked well for me. The main issue is that if you use the {% url ... %} template tag, you'll need a custom version that omits the prefix part of the URL.Emelina

© 2022 - 2024 — McMap. All rights reserved.