Django 会话过期?

18 投票
3 回答
19475 浏览
提问于 2025-04-15 14:01

根据Django的文档,我原本以为调用:

request.session.set_expiry(300)

从一个视图中会导致会话在五分钟内没有活动后过期;然而,我在Django的最新版本中并没有遇到这样的情况。如果我在一个视图中调用这个方法,然后再去浏览其他不调用这个方法的视图,会话还是在五分钟后过期。我原本期待的行为是,只有在五分钟内没有任何活动后才过期,而不是因为没有在过期前再次调用set_expiry。

所以我的问题是,我真的需要在每个视图中都调用set_expiry吗?如果是这样的话,有没有什么装饰器可以帮忙?我无法想象这不是Django的一个组成部分。

谢谢,
皮特

3 个回答

0

如果你在settings.py文件中把"SESSION_SAVE_EVERY_REQUEST"设置为"True",就会发生一个有趣的事情:每次你在Django网站上重新打开当前页面或者打开其他页面时,session(会话)都会自动更新。

SESSION_SAVE_EVERY_REQUEST = True # False by default

举个例子,假设session的有效时间是15分钟。那么从下午3:00开始,你在Django网站上登录,这时session会在下午3:15过期。接着,如果在下午3:10时,你重新打开当前页面或者打开其他页面,session就会被更新,这样新的session会在下午3:25过期。这就意味着你可以一直保持登录状态,直到下午3:25。换句话说,如果你没有重新打开页面或者没有打开其他页面,那么新的session会在下午3:25过期,这样你就会被登出,之后需要再次登录Django网站才能开始一个新的session

4

一个简单的中间件可能比在每个视图中单独设置要好。这是我使用的方式。

class SessionExpiry(object):
    """ Set the session expiry according to settings """
    def process_request(self, request):
        if getattr(settings, 'SESSION_EXPIRY', None):
            request.session.set_expiry(settings.SESSION_EXPIRY)
        return None

这取决于你的配置中是否设置了 SESSION_EXPIRY。它的格式和 request.session.set_expiry 是一样的。

MIDDLEWARE_CLASSES 的定义顺序要考虑到这一点:

MIDDLEWARE_CLASSES = (
    ...
    'django.contrib.sessions.middleware.SessionMiddleware',
    '<yourproject>.<yourapp>.middleware.SessionExpiry',
    ...
}

如果 django.contrib.sessions 默认能考虑到这个设置就好了。

33

作为这些方法的作者,我发现文档在这方面并不是很清楚。你的观察是对的:只有那些会改变会话的请求才算是“活动”。

你可以使用 SESSION_SAVE_EVERY_REQUEST 这个设置来实现你想要的效果(当然,这样每次请求都会保存会话,开销会比较大)。

注意:这样会更新现有的会话记录,并且会把过期时间更新为最新的。

撰写回答