开发者

Django hostname middleware gets cached

I created a Django project to manage two separate sites that share some backend code. Both of the sites are inside separate apps. Each app has its own models.py, views.py, templates etc...

To be able to react differently to different hostnames, I created an URLconf middleware:

class HostnameBasedUrlconfMiddleware(object):
    """This middleware parses the hostname from the request, and selects the
    urlconf acc开发者_JS百科ordingly.

    To set a custom urlconf according to the current hostname, add an URLCONF
    dictionary to your settings.py file.

    URLCONF = {
        'example.com': 'urls_example',
        'example.dev': 'urls_dev',
        'admin.example.dev': 'apps.admin.urls'
    }

    If the hostname is not found in the URLCONF dictionary, the default
    ROOT_URLCONF setting will be used.

    """

    def process_request(self, request):
        # Decide which urlconf to use. Fallback is to use the ROOT_URLCONF
        # as defined in the settings.py file.
        try:
            hostname = request.META['HTTP_HOST']
            request.urlconf = settings.URLCONF[hostname]
        except (KeyError, AttributeError):
            pass

        return None

This seemed to work at first, but then I became aware that some kind of caching must be happening.

When starting the server and requesting site A, it would show up. If I then request site B, site A shows up. Sometimes (but not always), after several reloads, site B would finally show up. After restarting the server and requesting site B, it would show up, but now site A would show site B content.

This happened with the builtin devserver as well as with gunicorn.

I tried to request the site with curl to avoid browser caching, no difference.

I also suspected it could be some kind of template name collision, but all templates are inside a uniquely named subfolder inside their respective template folders.

I don't have memcached installed and I'm not using any caching middleware.

What could be the problem? Is there some internal automatic caching going on?


Here is the code in question that substitutes in the urlconf (for 1.3 at least):

django.core.handlers.base:

class BaseHandler(object):

   [...snip...]

   def get_response(self, request):
        "Returns an HttpResponse object for the given HttpRequest"
        from django.core import exceptions, urlresolvers
        from django.conf import settings

        try:
            # Setup default url resolver for this thread, this code is outside
            # the try/except so we don't get a spurious "unbound local
            # variable" exception in the event an exception is raised before
            # resolver is set
            urlconf = settings.ROOT_URLCONF
            urlresolvers.set_urlconf(urlconf)
            resolver = urlresolvers.RegexURLResolver(r'^/', urlconf)
            try:
                response = None
                # Apply request middleware
                for middleware_method in self._request_middleware:
                    response = middleware_method(request)
                    if response:
                        break

                if response is None:
                    if hasattr(request, "urlconf"):
                        # Reset url resolver with a custom urlconf.
                        urlconf = request.urlconf
                        urlresolvers.set_urlconf(urlconf)
                        resolver = urlresolvers.RegexURLResolver(r'^/', urlconf)
    [...snip...]

So, it looks like it's just using the value directly from request.urlconf. And your middleware is setting the request value directly.

I'd install django-debug-toolbar to confirm whether or not the value for request.urlconf is a) being set or b) being changed along the way.

To make absolutely sure, why not change the code temporarily to something like:

            request.urlconf = settings.URLCONF[hostname]
            request.urlconf_set = datetime.datetime.now()

Then you can look at the values in the debug toolbar (or just output them in a template) to see what might be going on.

However, I would suggest instead of using middleware, that you simply set up different settings.py files for each domain. Then, in whatever web server you're using, set each one up to use its own .wsgi file, which points to its own settings file, like so:

settings_a.py:

from settings import *
ROOT_URLCONF = 'urls_a.py'

settings_b.py

from settings import *
ROOT_URLCONF = 'urls_b.py'
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜