views:

585

answers:

2

I'm using subdomains in django for user pages via a middleware hack in a similar way to what is described here: stackoverflow.com/questions/624827/in-a-django-web-application-how-do-you-give-users-their-own-subdomain

Now, I have the default django cache turned on for all pages for not-logged-in users. I had to disable the cache implicitly for user pages as it treated those pages just as if they were the / pages, e.g. filmaster.com and michuk.filmaster.com is the same page to django.

Do you know of any nice and easy way to force django to understand subdomains for caching? Or do you suggest I just cache each of the subdomain views explicitly?

Update: actually looked into that solution (stackoverflow.com/questions/624827/in-a-django-web-application-how-do-you-give-users-their-own-subdomain) and it's not exactly how we do it. We do not redirect. We want the url to stay in subdomain, so what we do is just call the views directly from the middleware.

You can see the details of the hacky implementation here: musielak.eu/public/film20/film20/core/middleware.py (user: justlookingaround, pass:film@ster -- yes, we're open source). And here is a jira for fixing the hack: jira.filmaster.org/browse/FLM-54 (but that's not entirely relevant to the problem - it's just to make sure you don't think we support crappy coding :P)

A: 

Unfortunately, I can't address your primary issue (caching the subdomains) except to say that everything I have read implies that Django can't handle this in any elegant manner. Its possible this has changed for version 1.1, but if so I haven't come across anything about it. In my particular application I can't cache the subdomains anyway, so I have not looked into what internal modifications might be required to make this work better.

However, regarding the manner of accessing subdomain views, another option you might consider is something like this:

class SubdomainMiddleware:
    """
    Make the company specified by the subdomain available to views for
    appropriate processing.
    """
    def process_request(self, request):
        """
        Populate a company attribute on the request object with the company
        indicated by the requested subdomain.
        """
        domain_parts = request.get_host().split('.')

        if (len(domain_parts) > 2):
            subdomain = domain_parts[0]

            if (subdomain.lower() == 'www'):
                subdomain = ''
        else:
            subdomain = ''

        if subdomain != '':
            try:
                request.company = Company.objects.get(subdomain=subdomain)
            except Company.DoesNotExist:
                return HttpResponseRedirect(''.join(['http://test.com', reverse('findcompany')]))                
        else:
            request.company = None

I think this is fairly self-explanatory--it is a heavily modified version of something I found on djangosnippets. It simply parses the subdomain, looks it up in the company table, and if that is a valid company it gets appended to the request object for handling by the view. This way, if test.com/test and sub.test.com/test are both valid then the view can contain that logic, rather than pushing it down into the middleware. Also, garbage subdomains are easily passed off to a search url.

I had intended to compare this to your middleware (more for my own education than anything else), but the URL you provided for your code returns a 404.

bouvard
The url is under ssl: https://musielak.eu/public/film20/film20 - I could not provide full urls before due to being a newbie in StackOverflow :)It uses a very similar logic to the one you provided actually, except for that there is way more nasty stuff happening after detecting the subdomain. We definitely need to rewrite that crap and apply some proper urls.py for subdomains.BTW, Filmaster is an open source project and you (as everyone else) are invited to join. You can read more at http://filmaster.org
michuk
A: 

OK, here is a fix that we actually used. It does unfortunately involve hacking Django code, in particular the _generate_cache_header_key method in django/trunk/django/utils/cache.py What we do is simply check if there is any subdomain in the HTTP host and if so, extract the subdomain from it and append it to the cache key. We could also simply append the host, which would work very much the same, but taking some more precious bits in RAM.

Here is the jira: http://jira.filmaster.org/browse/FLM-84 And here is the code used. Use at your own risk!

def _generate_cache_header_key(key_prefix, request):
    """
       Returns a cache key for the header cache.
       With Filmaster hack for handling subdomain caching: http://jira.filmaster.org/browse/FLM-84
    """
    subdomain = None
    path = request.path

    # TODO: this is not a decent implementation, it will work only on domains with one dot it them
    # To fix it, we'd need to pass a param to the request object before CacheMiddleware
    # this current domain name in it, and use that domain name in the regexp below
    m = re.match(r"([^\.]+)\.[^\.]+\.[^\.]+", request.META['HTTP_HOST'])
    if m!=None:
        subdomain = m.group(1)

    if subdomain != None:
        path = subdomain + "___" + path
    path = md5_constructor(iri_to_uri(path))
    return 'views.decorators.cache.cache_header.%s.%s' % (key_prefix, path.hexdigest())
michuk