只针对认证用户的Django缓存。

问题描述 投票:21回答:4

问题

在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')

settingtings.py(相关部分)

# 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的回答,我通过以下方法解决了这个问题。

  1. 创建一个 decorators.py 文件
  2. 在其中添加以下代码
  3. 导入函数 views.py
  4. 将它作为一个装饰器应用到我想要缓存的视图中,只对登录用户开放。

装饰者.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 并要求他们登录。

python django caching heroku memcached
4个回答
26
投票

默认的 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

如果用户没有经过认证。


2
投票

如果@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', {})

-1
投票

如果你想对缓存能力进行微调,我建议不要使用缓存中间件。

然而,如果你确实想坚持保持它,你可以尝试像(不是说它会像现在这样工作,而是类似的东西)。

@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。


-1
投票

我知道这是一个很老的问题,但我们有一个新的替代方案来解决这个问题。

你可以使用装饰器 cache_control 过路 private 作为 True 以保护您的数据。

© www.soinside.com 2019 - 2024. All rights reserved.