在Django中,如何创建一个只对认证用户可见的单一缓存版本的页面(对所有用户都一样)?
我想缓存的页面只对经过认证的用户开放(他们使用的是 @login_required
视图上的)。) 这些页面对所有经过认证的用户都是一样的(例如,不需要在视图上设置 vary_on_headers
基于唯一用户)。)
然而,我不希望这些缓存页面对非认证用户可见。
vary_on_headers
但我不需要为每个用户单独缓存页面。谢谢!
@login_required
@cache_page(60 * 60)
def index(request):
'''Display the home page'''
return render(request, 'index.html')
# Add the below for memcache
MIDDLEWARE_CLASSES += (
'django.middleware.cache.UpdateCacheMiddleware',
'django.middleware.cache.FetchFromCacheMiddleware',
)
# Enable memcache
# https://devcenter.heroku.com/articles/memcache#using_memcache_from_python
CACHES = {
'default': {
'BACKEND': 'django_pylibmc.memcached.PyLibMCCache'
}
}
根据@Tisho的回答,我通过以下方法解决了这个问题。
decorators.py
文件views.py
from functools import wraps
from django.views.decorators.cache import cache_page
from django.utils.decorators import available_attrs
def cache_on_auth(timeout):
def decorator(view_func):
@wraps(view_func, assigned=available_attrs(view_func))
def _wrapped_view(request, *args, **kwargs):
if request.user.is_authenticated():
return cache_page(timeout)(view_func)(request, *args, **kwargs)
else:
return view_func(request, *args, **kwargs)
return _wrapped_view
return decorator
对于已登录的用户,它会缓存页面(或为他们提供缓存页面)对于未登录的用户,它只是给他们提供常规的视图,该视图是用 @login_required
并要求他们登录。
默认的 cache_page
装饰器接受一个名为 key_prefix
. 然而,它只能作为一个字符串参数传递。因此,你可以写你自己的装饰器,它将动态地修改这个 prefix_key
基于 is_authenticated
值。下面是一个例子。
from django.views.decorators.cache import cache_page
def cache_on_auth(timeout):
def decorator(view_func):
@wraps(view_func, assigned=available_attrs(view_func))
def _wrapped_view(request, *args, **kwargs):
return cache_page(timeout, key_prefix="_auth_%s_" % request.user.is_authenticated())(view_func)(request, *args, **kwargs)
return _wrapped_view
return decorator
然后在视图中使用它。
@cache_on_auth(60*60)
def myview(request)
然后,生成的cache_key会是这样的:
cache key:
views.decorators.cache.cache_page._auth_False_.GET.123456.123456
如果用户是经过认证的,并且
cache key:
views.decorators.cache.cache_page._auth_True_.GET.789012.789012
如果用户没有经过认证。
如果@Tisho答案中的@wrap装饰器让你脑洞大开,或者说显式的解决方案比隐式的更好,这里有一个简单的程序方式来服务不同的缓存结果。
from django.views.decorators.cache import cache_page
def index(request):
"""
:type request: HttpRequest
"""
is_authenticated = request.user.is_authenticated()
if is_authenticated:
return render_user(request)
else:
return render_visitor(request)
@cache_page(5, key_prefix='user_cache')
def render_user(request):
print 'refreshing user_cache'
return render(request, 'home-user.html', {})
@cache_page(10, key_prefix='visitor_cache')
def render_visitor(request):
print 'refreshing visitor_cache'
return render(request, 'home-visitor.html', {})
如果你想对缓存能力进行微调,我建议不要使用缓存中间件。
然而,如果你确实想坚持保持它,你可以尝试像(不是说它会像现在这样工作,而是类似的东西)。
@never_cache
def dynamic_index(request):
# do dynamic stuff
def cached_index(request):
return dynamic_index(request)
@never_cache
def index(request):
if request.user.is_authenticaded():
return cached_index(request)
return dynamic_index(request)
最坏的情况下,你可以使用cache.set('view_name', template_rendering_result)和cache.get来手动缓存HTML。
我知道这是一个很老的问题,但我们有一个新的替代方案来解决这个问题。
你可以使用装饰器 cache_control 过路 private
作为 True
以保护您的数据。