作者: Django 团队 译者: 翻译开始日期: 2006-04-27 修订日期: 2006-04-27 原文版本: 2744

Django 完全支持匿名 session. session 框架允许每一个用户保存并取回数据. 它抽象发送及接收 cookies 并在服务器端保存数据. Cookie 中包含一个 session ID – 并不是数据本身.

启用 sessions

默认情况下, Session 功能就是启用的.

通过修改 MIDDLEWARE_CLASSES 设置你可以手工启用或关闭 session 功能.要激活 session 功能, 你要保证 MIDDLEWARE_CLASSES 包含 "django.contrib.sessions.middleware.SessionMiddleware".

如果你不想使用 sessions, 在 MIDDLEWARE_CLASSES 中移除 SessionMiddleware 行. 这会为你的系统减少一点负载.

在 views 中使用 session

每一个 HttpRequest 对象 – 即任意 Django view 函数的第一个参数 – 拥有一个 session 属性, 该属性是一个行为类似字典的可读写对象.

它实现了以下标准字典方法:

  • contains(key) 例子: ‘fav_color’ in request.session
  • getitem(key) 例子: fav_color = request.session[‘fav_color’]
  • setitem(key, value) 例子: request.session[‘fav_color’] = ‘blue’
  • delitem(key) 例子: del request.session[‘fav_color’]. This raises KeyError if the given key isn’t already in the session.
  • get(key, default=None) 例子: fav_color = request.session.get(‘fav_color’, ‘red’)
  • keys()
  • items()

它还拥有以下三个方法:

  • set_test_cookie() 设置一个测试 cookie 以判断用户浏览器是否支持 cookie. 由于 cookie 的工作方式, 除非得到用户的下一请求页面,你无法知道用户浏览器是否支持cookie. 阅读阅读下文中的 "Setting test cookies" 可以得到更多信息.
  • test_cookie_worked() 根据用户浏览器是否接受测试cookie 返回 True 或 False, 由于cookie 特殊的工作方式, 你必须在前一个独立的页面请求中调用 set_test_cookie() .阅读下文中的 "Setting test cookies" 可以得到更多信息.
  • delete_test_cookie() 删除测试 cookie. 可以用它来清理你的 cookie.

在你的 view 的任何部分都可以编辑 request.session , 你也可以在 view 中多次修改它的值.

Session 对象指南
  • 使用常规的 Python 字符串作为字典的 request.session 的 key. 这是一个使用惯例而不是硬性规定.
  • 下划线开头的 Session key 被保留为由 Django 内部使用.
  • 不要用一个新对象覆盖 request.session , 也不要访问或设置它的属性. 你应该一直把它当成一个字典来使用.
几个例子

下面这个极为简单的 view 在用户发表了一个评论之后将 has_commented 变量的值设置为 True . 它只允许用户发表一次评论:

def post_comment(request, new_comment):
if request.session.get(‘has_commented’, False):
return HttpResponse("You’ve already commented.")
c = comments.Comment(comment=new_comment)
c.save()
request.session[‘has_commented’] = True
return HttpResponse(‘Thanks for your comment!’)

下面这个 view 则用于一个站点的用户登录:

def login(request):
m = members.get_object(username__exact=request.POST[‘username’])
if m.password == request.POST[‘password’]:
request.session[‘member_id’] = m.id
return HttpResponse("You’re logged in.")
else:
return HttpResponse("Your username and password didn’t match.")

…这一个则根据上面的 login() 用于用户登出:

def logout(request):
try:
del request.session[‘member_id’]
except KeyError:
pass
return HttpResponse("You’re logged out.")设置测试 cookie

方便起见, Django 提供了一个简单有效的方式来测试用户浏览器是否接受 cookie .在一个 view 中调用 request.session.set_test_cookie() 然后在后面的view中调用 request.session.test_cookie_worked() – 注意不能是同一个 view 的两次调用.

这种看似笨拙将 set_test_cookie() 及 test_cookie_worked() 分成两步执行的方法是不得以的. 当你设置一个 cookie 以后,在浏览器的下一次请求之前,你无法知道浏览器是否接受了它.

在测试完毕之后, 及时使用 delete_test_cookie() 清理掉测试 cookie 是一个好习惯.

下面是一个典型应用的例子:

def login(request):
if request.POST:
if request.session.test_cookie_worked():
request.session.delete_test_cookie()
return HttpResponse("You’re logged in.")
else:
return HttpResponse("Please enable cookies and try again.")
request.session.set_test_cookie()
return render_to_response(‘foo/login_form.html’)在 view 之外使用 session

在系统内部, 每一个 session 都是一个 Django model. Session model 定义在 django/contrib/sessions/models.py. 因为它就是一个普通的 model ,你可以使用常规的 Django 数据库 API 访问 sessions.:

>>> from django.contrib.sessions.models import Session
>>> s = Session.objects.get_object(pk=‘2b1189a188b44ad18c35e113ac6ceead’)
>>> s.expire_date
datetime.datetime(2005, 8, 20, 13, 35, 12)

注意你需要调用 get_decoded() 来得到 session 字典. 这一步是必须的, 因为这个字典是被编码以后存储的:

>>> s.session_data
‘KGRwMQpTJ19hdXRoX3VzZXJfaWQnCnAyCkkxCnMuMTExY2ZjODI2Yj…’
>>> s.get_decoded()
{‘user_id’: 42}何时保存 session

默认情况下, Django 只在 session 被修改时保存 session 到数据库 – 也就是 session 被赋值或删除时:

# Session被修改
request.session[‘foo’] = ‘bar’

# Session被修改
del request.session[‘foo’]

# Session被修改
request.session[‘foo’] = {}

# Gotcha: Session 未被修改, 因为它改变的是
# request.session[‘foo’] 而不是 request.session.
request.session[‘foo’][‘bar’] = ‘baz’

要改变这种默认行为, 将 SESSION_SAVE_EVERY_REQUEST 设置为 True. 若 SESSION_SAVE_EVERY_REQUEST 为 True, Django 会在发生任何一次单独的请求时保存 session 到数据库.

注意 session cookie 仅当一个 session 变量被创建或修改时才将其发送到客户端.如果 SESSION_SAVE_EVERY_REQUEST 为 True, session cookie 就会在任何一次请求时被发送.

类似的, 一个 session cookie 的 expires 部分在发送 session cookie 时也将自动更新.

设置

几个 Django settings 允许你控制 session 的行为:

SESSION_COOKIE_AGE

默认值: 1209600 (2 周, 以秒计)

session cookie 的有效期, 以秒计.

SESSION_COOKIE_DOMAIN

默认值: None

使用 session cookie 的域. 如果要 session cookie 跨域工作, 将它设置为类似 ".lawrence.com" , 否则就设置为 None (标准cookie工作方式).

SESSION_COOKIE_NAME

默认值: ‘sessionid’

session cookie 的名字. 你可以任意设置.

SESSION_SAVE_EVERY_REQUEST

默认值: False

是否每次请求都保存 session 数据. 若值为 False (默认), 则仅当 session 内容改变时才保存 – 也就是, 当任何字典值被赋值或删除时.

技术细节
  • session 字典接受任何 pickleable Python 对象. 参阅 the pickle module 了解更多信息.
  • Session 数据被保存在数据库中的 django_session 表中.
  • Django 仅在需要时才发送 cookie . 如果你没有设置任何 session 数据, 它就不会发送任何 cookie.
URL 中的 Session ID

Django sessions 框架基于 cookie, 它完整并且独立. 它不会将 session id 放到 url 中作为最后的手段(PHP是那样). 我们故意让它这样(不使用url), 不仅仅是因为那种行为使得 url 很丑陋, 主要是因为那样会使得你的站点易被攻击.(通过 "Referer"头窃取 session-ID).