【问题标题】:Django - Multiple Sites Site CachingDjango - 多站点站点缓存
【发布时间】:2011-02-01 04:48:11
【问题描述】:

我在一个 Django 应用程序下有许多站点,我想在这些站点上实现站点范围的缓存。然而,事实证明这是一个真正的麻烦。

发生的情况是settings.CACHE_MIDDLEWARE_KEY_PREFIX 在启动时设置了一次,我无法继续根据当前站点的内容进行更改。因此,如果 url http://website1.com/abc/ 的页面被缓存,那么http://website2.com/abc/ 会呈现http://website1.com/abc/ 的缓存版本。这两个网站都在同一个 Django 实例上运行,因为 Django Sites 似乎允许我们这样做。

这是一种不正确的方法吗?因为我无法在运行时动态设置CACHE_MIDDLEWARE_KEY_PREFIX,所以我无法使用 Django 的站点范围缓存来缓存多个站点。我也无法为模板和视图缓存执行此操作。

我的印象是,真正需要设置的方式是每个站点都需要自己的 Django 实例,除了设置文件之外几乎相同,在我的情况下,设置文件的区别仅在于 CACHE_MIDDLEWARE_KEY_PREFIX 的值.这些 Django 实例都读取和写入同一个数据库。这让我很担心,因为它可能会产生许多新问题。

我是走在正确的轨道上还是我对多站点架构需要如何工作有误?我检查了 Django 文档,并没有真正提到如何为服务于多个站点的 Django 应用程序处理缓存(这不是低级缓存)。

【问题讨论】:

  • 你找到解决办法了吗?

标签: django django-sites django-caching


【解决方案1】:

(免责声明:以下内容纯属推测,未经测试。用少许盐食用。)

也许可以使用vary_on_headers 视图装饰器在缓存键中包含'Host' 标头。这应该会导致包含 HTTP Host 标头的缓存键,从而有效地隔离您的站点的缓存。

@vary_on_headers('Host')
def my_view(request):
    # ....

当然,这只适用于每个视图,并且必须为所有视图添加装饰器可能会很麻烦。

深入研究source of @vary_on_headers 揭示了patch_vary_headers() 的使用,可以在中间件中使用它来在站点级别应用相同的行为。大致如下:

from django.utils.cache import patch_vary_headers

class VaryByHostMiddleware(object):
    def process_response(self, request, response):
        patch_vary_headers(response, ('Host',))
        return response

【讨论】:

    【解决方案2】:

    我最近遇到了这个问题。我基于documentation 所做的是创建一个自定义方法来将站点ID 添加到用于缓存视图的键中。

    在 settings.py 中添加 KEY_FUNCTION 参数:

    CACHES = {
        'default': {
            'BACKEND': 'path.to.backend',
            'LOCATION': 'path.to.location',
            'TIMEOUT': 60,
            'KEY_FUNCTION': 'path.to.custom.make_key_per_site',
            'OPTIONS': {
                'MAX_ENTRIES': 1000
            }
        }
    }
    

    还有我自定义的 make_key 方法:

    def make_key_per_site(key, key_prefix, version):
        site_id = ''
        try:
            site = get_current_site() # Whatever you use to get your site's data
            site_id = site['id']
        except:
            pass
        return ':'.join([key_prefix, site_id, str(version), key])
    

    【讨论】:

    • get_current_site() 需要一个“请求”参数。这是个好主意,但最终行不通。
    【解决方案3】:

    你需要在 django.util.cache 中将 get_full_path 改为 build_absolute_uri

    def _generate_cache_header_key(key_prefix, request):
    """Returns a cache key for the header cache."""
    #path = md5_constructor(iri_to_uri(request.get_full_path()))
    path = md5_constructor(iri_to_uri(request.build_absolute_uri())) # patch using full path
    cache_key = 'views.decorators.cache.cache_header.%s.%s' % (
        key_prefix, path.hexdigest())
    return _i18n_cache_key_suffix(request, cache_key)
    
    
    def _generate_cache_key(request, method, headerlist, key_prefix):
    """Returns a cache key from the headers given in the header list."""
    ctx = md5_constructor()
    for header in headerlist:
        value = request.META.get(header, None)
        if value is not None:
            ctx.update(value)
    #path = md5_constructor(iri_to_uri(request.get_full_path()))
    path = md5_constructor(iri_to_uri(request.build_absolute_uri()))
    cache_key = 'views.decorators.cache.cache_page.%s.%s.%s.%s' % (
        key_prefix, request.method, path.hexdigest(), ctx.hexdigest())
    return _i18n_cache_key_suffix(request, cache_key)
    

    或者为多站点创建您自己的稍作更改的缓存中间件。 http://macrotoma.blogspot.com/2012/06/custom-multisite-caching-on-django.html

    【讨论】:

      猜你喜欢
      • 2018-01-27
      • 2012-01-07
      • 1970-01-01
      • 1970-01-01
      • 2019-08-29
      • 2012-03-30
      • 1970-01-01
      • 1970-01-01
      • 2016-12-24
      相关资源
      最近更新 更多