作者: | Django 团队 |
---|---|
译者: | weizhong2004@gmail.com |
翻译开始日期: | 2006-04-27 |
修订日期: | 2006-04-27 |
原文版本: | 2744 |
Django 完全支持匿名 session. session 框架允许每一个用户保存并取回数据. 它抽象发送及接收 cookies 并在服务器端保存数据. Cookie 中包含一个 session ID -- 并不是数据本身.
默认情况下, Session 功能就是启用的.
通过修改 MIDDLEWARE_CLASSES 设置你可以手工启用或关闭 session 功能.要激活 session 功能, 你要保证 MIDDLEWARE_CLASSES 包含 "django.contrib.sessions.middleware.SessionMiddleware".
如果你不想使用 sessions, 在 MIDDLEWARE_CLASSES 中移除 SessionMiddleware 行. 这会为你的系统减少一点负载.
每一个 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 中多次修改它的值.
- 使用常规的 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.")
方便起见, 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')
在系统内部, 每一个 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}
默认情况下, 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 的行为:
默认值: None
使用 session cookie 的域. 如果要 session cookie 跨域工作, 将它设置为类似 ".lawrence.com" , 否则就设置为 None (标准cookie工作方式).
默认值: False
是否每次请求都保存 session 数据. 若值为 False (默认), 则仅当 session 内容改变时才保存 -- 也就是, 当任何字典值被赋值或删除时.
- session 字典接受任何 pickleable Python 对象. 参阅 the pickle module 了解更多信息.
- Session 数据被保存在数据库中的 django_session 表中.
- Django 仅在需要时才发送 cookie . 如果你没有设置任何 session 数据, 它就不会发送任何 cookie.
Django sessions 框架基于 cookie, 它完整并且独立. 它不会将 session id 放到 url 中作为最后的手段(PHP是那样). 我们故意让它这样(不使用url), 不仅仅是因为那种行为使得 url 很丑陋, 主要是因为那样会使得你的站点易被攻击.(通过 "Referer"头窃取 session-ID).