【问题标题】:Django: setting a session and getting session key in same viewDjango:在同一视图中设置会话并获取会话密钥
【发布时间】:2011-07-05 01:51:07
【问题描述】:

我想在数据库中存储一些东西,并使用当前会话作为外键: 来自models.py

class Visited(models.Model):
    session = models.ForeignKey(Session)
    page = models.ForeignKey(Page)
    times_visited = models.PositiveIntegerField()
    ip_address = models.IPAddressField()
    date_last_visited = models.DateTimeField()
    def __unicode__(self):
        return u'(%s, %s)' % (str(self.session.session_key), str(self.page.name))

要为此模型创建一个新条目,我使用以下内容来获取当前会话(在 views.py 中):

Session.objects.get(session_key=request.session.session_key)

但是,如果这是用户第一次访问该网站,因此还没有设置 cookie,上面的代码将产生 DoesNotExist 错误。


我知道即使现在设置了 cookie,您仍然可以设置会话对象。所以我可以想出一些技巧来完成这项工作,例如:

  • 将唯一标识符设置为会话对象(除了会话密钥)
  • 将我希望添加到数据库的数据临时存储为会话对象,并在使用会话之前使用装饰器函数检查它是否存在。
  • 只使用会话对象而不在数据库中存储任何内容(这在技术上是可行的,但对于我的实现而言,它取决于 Python 字典 - 有几百个条目 - 至少与数据库一样高效,例如排序。)


但我想要一个更好的解决方案,我可以接受。这个问题有没有普遍使用或好的解决方案?还是我什至在我的模型中正确引用了会话?

感谢您的帮助。

【问题讨论】:

    标签: django django-models django-sessions


    【解决方案1】:

    request.session 是具有唯一 session_key 的 SessionStore object

    一旦访问属性,就会创建 session_key。但是会话对象本身只有在视图处理完毕后(在会话中间件的 process_response 方法中)通过调用 SessionStore 对象的 save 方法保存到数据库中。

    它并没有真正记录在案,但是查看源代码我猜你应该像这样创建一个新的会话对象:

    if not request.session.exists(request.session.session_key):
        request.session.create() 
    

    您还可以创建自定义会话中间件,以确保您的新会话对象在您的任何视图尝试访问它之前始终可用:

    from django.conf import settings
    from django.contrib.sessions.middleware import SessionMiddleware
    
    class CustomSessionMiddleware(SessionMiddleware):
        def process_request(self, request):
            engine = import_module(settings.SESSION_ENGINE)
            session_key = request.COOKIES.get(settings.SESSION_COOKIE_NAME, None)
            request.session = engine.SessionStore(session_key)
            if not request.session.exists(request.session.session_key):
                request.session.create() 
    

    (当然,您必须通过 settings.py 中的 SESSION_ENGINE 引用您的新会话中间件)

    但请注意 - 如果用户的浏览器不支持 cookie,此方法将为每个请求生成一个新的会话对象...

    【讨论】:

    • 感谢您对这一切如何运作(或者更确切地说为什么它不起作用)的出色解释。我选择了我提到的第二个“hack”的变体,为了简洁而不是优雅。
    • 我对 Django 或 Python 不太熟悉,但我很确定这个答案正是我所需要的。如果从客户端传递了会话 ID(不要问),我需要换出会话。我有点困惑,除了'django.contrib.sessions.middleware.SessionMiddleware'和SESSION_ENGINE之外,我是否在MIDDLEWARE_CLASSES中引用了这个类?肯定在SESSION_ENGINE 中引用它会导致这条线递归? engine = import_module(settings.SESSION_ENGINE)。我错过了重点吗?
    • 我不认为request.session.create() 设置了Set-Cookie 标头。
    • 为了阻止 SessionMiddleWare 运行 delete_cookie,我必须在会话中设置一些内容,例如 request.session['foo'] = 'bar'
    • 这很有帮助。不敢相信(截至今天)这不在 django 文档中。似乎执行 .clear() 然后 .create() 来清除用户历史记录将是一个足够常见的事件。
    【解决方案2】:

    如果你想销毁会话,我建议一个更好的主意是首先使用 django shell。

    from django.contrib.sessions.models import Session
    Session.objects.all() #you see all sessions
    Session.objects.all().delete() 
    

    在最后一个查询中,您可以根据需要进行过滤。并点击查询

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-06-01
      • 2021-09-02
      • 2017-12-10
      • 2011-06-25
      • 1970-01-01
      • 2013-07-16
      • 2012-06-26
      • 1970-01-01
      相关资源
      最近更新 更多