Django caching for subdomains

2019-04-02 08:17发布

I'm using subdomains in django for user pages via a middleware hack in a similar way to what is described here:

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 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 [Update:404 page not found] (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)

2条回答
SAY GOODBYE
2楼-- · 2019-04-02 08:52

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.

查看更多
时光不老,我们不散
3楼-- · 2019-04-02 09:03

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()) 
查看更多
登录 后发表回答