为什么Django 1.4每站点缓存无法正常使用CACHE_MIDDLEWARE_ANONYMOUS_ONLY?

时间:2012-08-21 17:30:11

标签: django

我正在研究Django 1.4项目并使用每站点缓存编写一个简单的应用程序,如下所述:

https://docs.djangoproject.com/en/dev/topics/cache/#the-per-site-cache

我已正确设置本地Memcached服务器并确认正在缓存页面。

然后我设置CACHE_MIDDLEWARE_ANONYMOUS_ONLY = True,因为我不想为经过身份验证的用户缓存页面。

我正在使用一个简单的视图进行测试,该视图返回一个带有render_to_response和RequestContext的模板,以便能够从模板访问用户信息,并且缓存目前运行良好,这意味着它只为匿名用户缓存页面。

这是我的问题。我使用不访问用户信息的不同模板创建了另一个视图,并注意到即使用户已通过身份验证也正在缓存该页面。在测试了很多东西后,我发现如果模板没有从用户上下文变量中打印出某些东西,那么经过身份验证的用户就会获得一个缓存页面。测试非常简单:在模板上打印用户,不会为经过身份验证的用户缓存页面,删除模板上的用户,在进行身份验证时刷新页面并检查HTTP标头,您会注意到缓存页面。您应该清除更改之间的缓存以更清楚地查看问题。

我测试了一点,发现我可以在模板中删除用户并在视图上打印request.user(打印到开发服务器控制台)并且还修复了显示缓存页面的问题对于经过身份验证的用户,但这是一个丑陋的黑客。

此处报告了一个类似的问题,但从未得到答案:

https://groups.google.com/d/topic/django-users/FyWmz9csy5g/discussion

我可以编写一个条件装饰器来检查user.is_authenticated()并基于它在我的视图上使用@never_cache但是看起来这样会破坏使用每站点缓存的目的,不是吗?

"""
A decorator to bypass per-site cache if the user is authenticated. Based on django.views.decorators.cache.never_cache.
See: http://stackoverflow.com/questions/12060036/why-django-1-4-per-site-cache-does-not-work-correctly-with-cache-middleware-anon
"""     

from django.utils.decorators import available_attrs
from django.utils.cache import add_never_cache_headers
from functools import wraps

def conditional_cache(view_func):
    """
    Checks the user and if it's authenticated pass it through never_cache.
    This version uses functools.wraps for the wrapper function.
    """ 
    @wraps(view_func, assigned=available_attrs(view_func))
    def _wrapped_view_func(request, *args, **kwargs):
        response = view_func(request, *args, **kwargs)
        if request.user.is_authenticated():
            add_never_cache_headers(response)
        return response
    return _wrapped_view_func

任何避免需要额外装饰的建议都将受到赞赏。

谢谢!

1 个答案:

答案 0 :(得分:0)

好的,我刚刚确认我的“问题”是由Django延迟加载User对象引起的。

为了确认,我刚刚在我的观点中添加了这样的内容:

test_var =“some text”+ request.user

我收到一条错误消息,告诉我无法将str连接到SimpleLazyObject。此时,延迟加载逻辑还没有真正的User对象。

为了绕过延迟加载,因此为经过身份验证的用户返回非缓存视图,我只需要访问某个方法或属性来触发User对象的实际查询。我最终得到了这个,我认为这是最简单的方法:

bypass_lazyload = request.user.is_authenticated()

我不再需要我的conditional_cache装饰器,尽管这是一个有趣的练习。

当我完成视图处理时,我可能不需要这样做,因为我会在我的模板上访问一些用户方法和属性,但是知道发生了什么事情很好。

问候。