2011-02-27 83 views
17

我想有些东西存储在数据库中,和现在用的是当前会话外键:从models.py Django的:设置会话和获取会话密钥在相同的观点

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) 

但是,如果这是用户第一次访问过该网站,因而不具备上面的代码会产生一个DoesNotExist错误。


我知道,即使是现在的cookie设置,你仍然可以设置会话对象。所以,我能想到的几个黑客,使这项工作,如:

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


但我想一个更好的解决方案,我可以住在一起。有什么常用或很好的解决方案来解决这个问题吗?或者我甚至在我的模型中正确引用会话?

谢谢你的帮助。

回答

39

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

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

这不是真正的记载,但查看源代码,我猜你应该建立这样一个新的会话对象:

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() 

(当然,你必须通过SESSION_ENIGNE引用里面的settings.py新的会话中间件)

但要注意 - 这种方法会产生,如果用户的浏览器不支持cookie每个请求一个新的会话对象...

+0

感谢您的优秀解释它是如何工作(或者说为什么它不”工作)。我带着我提到的第二个“黑客”的变体,为了简单起见,如果不是优雅。 – 2011-02-27 13:55:54

+0

我对Django或Python不太熟悉,但我确信这个答案正是我需要的。如果会话ID从客户端传递(我不问),我需要换出会话。我有点困惑,除了'django.contrib.sessions.middleware.SessionMiddleware'还有'SESSION_ENGINE',我是否在'MIDDLEWARE_CLASSES'中引用这个类?当然在'SESSION_ENGINE'中引用它会导致这条线递归? 'engine = import_module(settings.SESSION_ENGINE)'。我错过了这一点吗? – Steve 2014-08-05 09:21:11

+0

我不认为'request.session.create()'设置了'Set-Cookie'标题。 – Flimm 2016-01-13 17:03:44