如何使Django中的cache_page无效



问题是:我有一个博客应用程序,我缓存了5分钟的post输出视图。

@cache_page(60 * 5)
def article(request, slug):
    ...

然而,每当有新的评论添加到帖子中时,我想使缓存无效。我想知道如何最好地做到这一点?

我看过这个相关的问题,但它已经过时了。

这是我在搜索解决方案时的第一次尝试,而当前的答案并没有太大帮助,所以在仔细研究了Django的源代码后,我找到了这个答案。

是的,您可以通过编程方式知道密钥,但这需要一些工作。

Django的页面缓存通过引用request对象来工作,特别是请求路径和查询字符串。这意味着对于具有不同查询字符串的每个页面请求,您将具有不同的缓存键。在大多数情况下,这不太可能是一个问题,因为你想要缓存/无效的页面将是一个已知的字符串,比如/blog/my-awesome-year,所以要使其无效,你只需要使用Django的RequestFactory:

from django.core.cache import cache
from django.test import RequestFactory
from django.urls import reverse
from django.utils.cache import get_cache_key

cache.delete(get_cache_key(RequestFactory().get("/blog/my-awesome-year")))

如果您的URL是一个固定的值列表(即没有不同的查询字符串),那么您可以到此为止。但是,如果您有很多不同的查询字符串(比如搜索页面的?q=xyz),那么最好的选择可能是为每个视图创建一个单独的缓存。然后您可以将cache="cachename"传递给cache_page(),然后使用清除整个缓存

from django.core.cache import caches

caches["my_cache_name"].clear()

关于此策略的重要说明

它只适用于未经验证的页面。用户登录后,cookie数据就成为缓存密钥创建过程的一部分,因此以编程方式重新创建该密钥变得更加困难。我想你可以尝试从会话存储中提取cookie数据,但其中可能有数千个密钥,你必须使它们中的每一个失效/预缓存。

我会用一种不同的方式缓存:

def article(request, slug):
    cached_article = cache.get('article_%s' % slug)
    if not cached_article:
        cached_article = Article.objects.get(slug=slug)
        cache.set('article_%s' % slug, cached_article, 60*5)
    return render(request, 'article/detail.html', {'article':cached_article})

然后将新评论保存到本文对象:

# ...
# add the new comment to this article object, then
if cache.get('article_%s' % article.slug): 
    cache.delete('article_%s' % article.slug)
# ...

深入代码后,很明显我们可以做到这一点,但我们需要有您想要无效的API URL(带有查询和头),这看起来有点不可能,但如果是的话,Django使用md5作为哈希键,您可以尝试使用与头完全相同的URL生成相同的哈希。

def _generate_cache_key(request, method, headerlist, key_prefix):
"""Return a cache key from the headers given in the header list."""
ctx = hashlib.md5()
for header in headerlist:
    value = request.META.get(header)
    if value is not None:
        ctx.update(value.encode())
url = hashlib.md5(iri_to_uri(request.build_absolute_uri()).encode('ascii'))
cache_key = 'views.decorators.cache.cache_page.%s.%s.%s.%s' % (
    key_prefix, method, url.hexdigest(), ctx.hexdigest())
return _i18n_cache_key_suffix(request, cache_key)

这看起来并不容易,然后你可以为你拥有的每个URL设置一个前缀,找到所有具有相同前缀的密钥,并逐一删除它们,这是一个更好的选择。

cache_page(DEFAULT_TIMEOUT, None, 'your-cache-prefix')

我不建议每次你想显示未缓存的数据时都更改查询参数,但是的,还有一种方法,当你想要新数据时,你可以不传递缓存头。它将在默认情况下工作。

只是一张纸条

头没有缓存,同时修改查询参数永远不会使实际的缓存无效。

相关内容

  • 没有找到相关文章

最新更新