=================== 如何使用 session =================== :作者: Django 团队 :译者: weizhong2004@gmail.com :翻译开始日期: 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 内容改变时才保存 -- 也就是, 当任何字典值被赋值或删除时. .. _Django settings: http://www.djangoproject.com/documentation/settings/ 技术细节 ================= * session 字典接受任何 pickleable Python 对象. 参阅 `the pickle module`_ 了解更多信息. * Session 数据被保存在数据库中的 ``django_session`` 表中. * Django 仅在需要时才发送 cookie . 如果你没有设置任何 session 数据, 它就不会发送任何 cookie. .. _`the pickle module`: http://www.python.org/doc/current/lib/module-pickle.html URL 中的 Session ID =================== Django sessions 框架基于 cookie, 它完整并且独立. 它不会将 session id 放到 url 中作为最后的手段(PHP是那样). 我们故意让它这样(不使用url), 不仅仅是因为那种行为使得 url 很丑陋, 主要是因为那样会使得你的站点易被攻击.(通过 "Referer"头窃取 session-ID).