【问题标题】:Django hostname middleware gets cachedDjango 主机名中间件被缓存
【发布时间】:2011-08-23 16:40:07
【问题描述】:

我创建了一个 Django 项目来管理共享一些后端代码的两个独立站点。这两个网站都在不同的应用程序中。每个应用都有自己的 models.py、views.py、模板等...

为了能够对不同的主机名做出不同的反应,我创建了一个 URLconf 中间件:

class HostnameBasedUrlconfMiddleware(object):
    """This middleware parses the hostname from the request, and selects the
    urlconf accordingly.

    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

起初这似乎可行,但后来我意识到必须进行某种缓存。

当启动服务器并请求站点 A 时,它会显示出来。如果我随后请求站点 B,则会出现站点 A。有时(但不总是),经过几次重新加载后,站点 B 最终会出现。重新启动服务器并请求站点 B 后,它会显示出来,但现在站点 A 会显示站点 B 的内容。

这发生在内置开发服务器和 gunicorn 中。

我尝试用 curl 请求站点以避免浏览器缓存,没有区别。

我还怀疑这可能是某种模板名称冲突,但所有模板都位于各自模板文件夹内的一个唯一命名的子文件夹中。

我没有安装 memcached,也没有使用任何缓存中间件。

可能是什么问题?是否正在进行一些内部自动缓存?

【问题讨论】:

  • 您如何为您的单独主机名提供服务?
  • 目前通过主机文件。一旦投入生产,它将立即切换到普通 DNS。两个域都应该通过同一个 Django 实例提供服务。
  • 我遇到了同样的问题,这让我抓狂。我很欣赏乔丹的回应,但它没有回答你的问题。如果我能回答你的问题,那会让我的生活轻松很多。 :)
  • 我将在这个问题上创建一个赏金,看看是否有人可以给出更好的答案。
  • 就在我为赏金写出信息时,我回到我的系统中重新复制了几次以包含更多细节,但现在我无法在我的一生中复制它。我现在完全糊涂了……如果它再次发生,我会回来的。

标签: django caching middleware


【解决方案1】:

这里是 urlconf 中的替代代码(至少对于 1.3):

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...]

所以,看起来它只是直接使用来自request.urlconf 的值。而你的中间件是直接设置request 值。

我会安装 django-debug-toolbar 以确认 request.urlconf 的值是 a) 正在设置还是 b) 正在更改。

为了绝对确定,为什么不暂时将代码更改为:

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

然后您可以查看调试工具栏中的值(或将它们输出到模板中)以了解可能发生的情况。

但是,我建议您不要使用中间件,而是为每个域设置不同的 settings.py 文件。然后,在您使用的任何 Web 服务器中,将每个服务器设置为使用自己的 .wsgi 文件,该文件指向自己的设置文件,如下所示:

settings_a.py

from settings import *
ROOT_URLCONF = 'urls_a.py'

settings_b.py

from settings import *
ROOT_URLCONF = 'urls_b.py'

【讨论】:

  • 我已经通过在中间件末尾输出当前的 request.urlconf 来调试工具栏。我很确定该值设置正确。但我发现创建两个不同的设置文件是有意义的。我们已经为开发和生产使用了两个设置文件,通过将相似之处抽象到一个通用设置文件中,它可以很好地工作。
  • 您的帖子并没有真正揭示/解决问题,但分离 settings.py 文件的想法有所帮助。谢谢!
猜你喜欢
  • 2012-05-02
  • 2011-05-28
  • 1970-01-01
  • 2011-05-08
  • 1970-01-01
  • 2014-12-22
  • 2012-09-16
  • 1970-01-01
  • 2023-03-18
相关资源
最近更新 更多