2

我正在开发一个 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

任何避免需要额外装饰器的建议将不胜感激。

谢谢!

4

1 回答 1

0

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

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

test_var = "一些文本" + request.user

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

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

bypass_lazyload = request.user.is_authenticated()

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

当我完成对视图的处理时,我可能不需要这样做,因为无论如何我都会访问我的模板上的一些用户方法和属性,但很高兴知道发生了什么。

问候。

于 2012-08-23T13:21:02.597 回答