3

我目前正在使用 django 开发一个应用程序,每次在渲染视图或模板时出现错误,我的会话都会被注销。这最终很烦人。如何禁用此“功能”?请注意,如果在加载/解析代码时出现错误(例如,如果视图上的装饰器失败),我不会被注销,只有在视图中出现错误时。

编辑:我刚刚测试过,是的,从某种意义上说raise Exception确实会导致这种情况。

我所有的观点都被一个装饰器包裹着,其中包括:

def needs_base_index_dict(func):
    def wrapper(request, *args, **kwargs):
        request.session.set_expiry(30*60)
        #...

如果我注释掉该set_expiry行,那么我不会得到这种行为。当我修复错误时,我仍然处于登录状态。如果该行没有被注释掉,那么视图中的任何错误(包括raise Exception())都会注销会话。

4

3 回答 3

4

Django 基本上会在每次发生更改时将会话写入数据库。由于您正在视图装饰器中更新会话状态,这意味着应该有一个会话写入数据库。

但是,如果您使用的是具有事务管理的数据库,那么当您的视图失败时,您的数据库写入会回滚。但是,您的会话 cookie 过期时间已在您的浏览器上更新。这意味着您的浏览器会话和存储在服务器上的会话不再匹配。这种不一致会导致会话被丢弃并且您被注销。

这也解释了为什么当您注释掉该行时它可以正常工作。

如果您使用 django dev 服务器,那么您应该能够在控制台中看到您的查询。发生错误时查看会话更新查询是否运行成功。如果没有,您将知道为什么要注销:)

这是所需的行为,但如果您想在调试环境中禁用它,则只需在装饰器的相关行上方添加对 DEBUG 的检查。或者,您可以禁用事务管理(不推荐)。

于 2012-07-13T06:27:28.137 回答
3

不是为什么的答案,而是一种解决方法:

def needs_base_index_dict(func):
    def wrapper(request, *args, **kwargs):
        #... do the work
        func(*args, **kwargs)
        #... then set the expiry
        request.session.set_expiry(30*60)
于 2012-07-11T07:13:41.383 回答
0

您在评论中说您在错误页面中也获得了 set-cookie 标头。会话对象看起来没问题吗?在会话文档中,它说您可以像访问任何其他数据库对象一样访问基于数据库的会话。

from django.contrib.sessions.models import Session
s = Session.objects.get(pk='2b1189a188b44ad18c35e113ac6ceead')

如果该会话是针对匿名用户的,那么我愿意称这是一个非常有趣的功能。如果这是一个完全有效的会话,但不知何故,您似乎不再登录,则处理会话 cookie 时存在错误。

于 2012-07-10T07:31:29.780 回答