{"title":"如何使用会话","version":"4.1","locale":"zh-hans","docname":"topics/http/sessions","url":"/zh-hans/4.1/topics/http/sessions/","canonical":"https://djangodocs.dev/zh-hans/4.1/topics/http/sessions/","summary":"Django 是支持匿名会话的。会话框架允许您基于每个站点访问者存储和检索任意数据。它在服务器端存储数据并提供cookie的发送和接收。","html":"<span id=\"how-to-use-sessions\"></span><h1>如何使用会话<a class=\"heading-anchor\" href=\"#module-django.contrib.sessions\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h1>\n<p>Django 是支持匿名会话的。会话框架允许您基于每个站点访问者存储和检索任意数据。它在服务器端存储数据并提供cookie的发送和接收。Cookie包含会话ID - 而不是数据本身（除非您使用基于cookie的后端）。</p>\n<section id=\"enabling-sessions\">\n<h2>打开会话<a class=\"heading-anchor\" href=\"#enabling-sessions\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>会话通过配置一个中间件实现的</p>\n<p>为了打开会话，需要做下面的操作</p>\n<ul class=\"simple\">\n<li><p>编辑设置中的 MIDDLEWARE，并确保他包含了 'django.contrib.sessions.middleware.SessionMiddleware'。通过 django-admin startproject 创建的默认 settings.py 文件是已经打开了 SessionMiddleware 这项设置的。</p></li>\n</ul>\n<p>如果你不想使用会话功能，你可以从配置的 MIDDLEWARE 中删除 `SessionMiddleware，并且从 INSTALLED_APPS 中删除 'django.contrib.sessions'。它将会为您节省一点开销。</p>\n</section>\n<section id=\"configuring-the-session-engine\">\n<span id=\"configuring-sessions\"></span><h2>配置会话(session)引擎<a class=\"heading-anchor\" href=\"#configuring-the-session-engine\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>默认情况下，Django 在数据库里存储会话（使用 <code class=\"docutils literal notranslate\">django.contrib.sessions.models.Session</code> ）。虽然这很方便，但在一些设置里，在其他地方存储会话数据速度更快，因此 Django 可以在文件系统或缓存中配置存储会话数据。</p>\n<section id=\"using-database-backed-sessions\">\n<h3>使用数据库支持的会话<a class=\"heading-anchor\" href=\"#using-database-backed-sessions\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>如果你想使用数据库支持的会话，你需要在 <a class=\"reference internal\" href=\"/zh-hans/4.1/ref/settings/#std-setting-INSTALLED_APPS\"><code class=\"xref std std-setting docutils literal notranslate\">INSTALLED_APPS</code></a> 里添加 <code class=\"docutils literal notranslate\">'django.contrib.sessions'</code> 。</p>\n<p>一旦在安装中配置，运行 <code class=\"docutils literal notranslate\">manage.py migrate</code> 来安装单个数据库表来存储会话数据。</p>\n</section>\n<section id=\"using-cached-sessions\">\n<span id=\"cached-sessions-backend\"></span><h3>使用缓存会话<a class=\"heading-anchor\" href=\"#using-cached-sessions\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>为了得到更好的性能，你可以使用基于缓存的会话后端。</p>\n<p>使用 Django 的缓存系统来存储会话，你首先需要确保已经配置了缓存，查看 <a class=\"reference internal\" href=\"/zh-hans/4.1/topics/cache/\"><span class=\"doc\">cache documentation</span></a> 获取详情。</p>\n<aside class=\"admonition admonition-warning\" role=\"note\">\n<p class=\"admonition-title\">Warning</p>\n<p>You should only use cache-based sessions if you're using the Memcached or\nRedis cache backend. The local-memory cache backend doesn't retain data\nlong enough to be a good choice, and it'll be faster to use file or\ndatabase sessions directly instead of sending everything through the file\nor database cache backends. Additionally, the local-memory cache backend is\nNOT multi-process safe, therefore probably not a good choice for production\nenvironments.</p>\n</aside>\n<p>如果你在 <a class=\"reference internal\" href=\"/zh-hans/4.1/ref/settings/#std-setting-CACHES\"><code class=\"xref std std-setting docutils literal notranslate\">CACHES</code></a> 定义了多缓存，Django 会使用默认缓存。如果要使用其他缓存，请将 <a class=\"reference internal\" href=\"/zh-hans/4.1/ref/settings/#std-setting-SESSION_CACHE_ALIAS\"><code class=\"xref std std-setting docutils literal notranslate\">SESSION_CACHE_ALIAS</code></a> 设置为该缓存名。</p>\n<p>Once your cache is configured, you have to choose between a database-backed\ncache or a non-persistent cache.</p>\n<p>The cached database backend (<code class=\"docutils literal notranslate\">cached_db</code>) uses a write-through cache --\nsession writes are applied to both the cache and the database. Session reads\nuse the cache, or the database if the data has been evicted from the cache. To\nuse this backend, set <a class=\"reference internal\" href=\"/zh-hans/4.1/ref/settings/#std-setting-SESSION_ENGINE\"><code class=\"xref std std-setting docutils literal notranslate\">SESSION_ENGINE</code></a> to\n<code class=\"docutils literal notranslate\">&quot;django.contrib.sessions.backends.cached_db&quot;</code>, and follow the configuration\ninstructions for the <a class=\"reference internal\" href=\"#using-database-backed-sessions\">using database-backed sessions</a>.</p>\n<p>The cache backend (<code class=\"docutils literal notranslate\">cache</code>) stores session data only in your cache. This is\nfaster because it avoids database persistence, but you will have to consider\nwhat happens when cache data is evicted. Eviction can occur if the cache fills\nup or the cache server is restarted, and it will mean session data is lost,\nincluding logging out users. To use this backend, set <a class=\"reference internal\" href=\"/zh-hans/4.1/ref/settings/#std-setting-SESSION_ENGINE\"><code class=\"xref std std-setting docutils literal notranslate\">SESSION_ENGINE</code></a>\nto <code class=\"docutils literal notranslate\">&quot;django.contrib.sessions.backends.cache&quot;</code>.</p>\n<p>The cache backend can be made persistent by using a persistent cache, such as\nRedis with appropriate configuration. But unless your cache is definitely\nconfigured for sufficient persistence, opt for the cached database backend.\nThis avoids edge cases caused by unreliable data storage in production.</p>\n</section>\n<section id=\"using-file-based-sessions\">\n<h3>使用基于文件的会话<a class=\"heading-anchor\" href=\"#using-file-based-sessions\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>要使用基于文件的会话，需要设置 <a class=\"reference internal\" href=\"/zh-hans/4.1/ref/settings/#std-setting-SESSION_ENGINE\"><code class=\"xref std std-setting docutils literal notranslate\">SESSION_ENGINE</code></a> 为 <code class=\"docutils literal notranslate\">&quot;django.contrib.sessions.backends.file&quot;</code> 。</p>\n<p>You might also want to set the <a class=\"reference internal\" href=\"/zh-hans/4.1/ref/settings/#std-setting-SESSION_FILE_PATH\"><code class=\"xref std std-setting docutils literal notranslate\">SESSION_FILE_PATH</code></a> setting (which\ndefaults to output from <code class=\"docutils literal notranslate\">tempfile.gettempdir()</code>, most likely <code class=\"docutils literal notranslate\">/tmp</code>) to\ncontrol where Django stores session files. Be sure to check that your web\nserver has permissions to read and write to this location.</p>\n</section>\n<section id=\"using-cookie-based-sessions\">\n<span id=\"cookie-session-backend\"></span><h3>使用基于cookie的会话<a class=\"heading-anchor\" href=\"#using-cookie-based-sessions\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>要使用基于cookies的会话，需要设置 <a class=\"reference internal\" href=\"/zh-hans/4.1/ref/settings/#std-setting-SESSION_ENGINE\"><code class=\"xref std std-setting docutils literal notranslate\">SESSION_ENGINE</code></a> 为 <code class=\"docutils literal notranslate\">&quot;django.contrib.sessions.backends.signed_cookies&quot;</code> 。这个会话数据将使用 Django 的加密工具( <a class=\"reference internal\" href=\"/zh-hans/4.1/topics/signing/\"><span class=\"doc\">cryptographic signing</span></a> ) 和 <a class=\"reference internal\" href=\"/zh-hans/4.1/ref/settings/#std-setting-SECRET_KEY\"><code class=\"xref std std-setting docutils literal notranslate\">SECRET_KEY</code></a> 工具进行保存。</p>\n<aside class=\"admonition admonition-note\" role=\"note\">\n<p class=\"admonition-title\">Note</p>\n<p>建议将 <a class=\"reference internal\" href=\"/zh-hans/4.1/ref/settings/#std-setting-SESSION_COOKIE_HTTPONLY\"><code class=\"xref std std-setting docutils literal notranslate\">SESSION_COOKIE_HTTPONLY</code></a> 设置为 <code class=\"docutils literal notranslate\">True</code> 来防止通过 JavaScript 访问存储数据。</p>\n</aside>\n<aside class=\"admonition admonition-warning\" role=\"note\">\n<p class=\"admonition-title\">Warning</p>\n<p><strong>If the</strong> <code class=\"docutils literal notranslate\">SECRET_KEY</code> <strong>or</strong> <code class=\"docutils literal notranslate\">SECRET_KEY_FALLBACKS</code> <strong>are not kept\nsecret and you are using the</strong>\n<code class=\"docutils literal notranslate\">django.contrib.sessions.serializers.PickleSerializer</code>, <strong>this can lead\nto arbitrary remote code execution.</strong></p>\n<p>An attacker in possession of the <a class=\"reference internal\" href=\"/zh-hans/4.1/ref/settings/#std-setting-SECRET_KEY\"><code class=\"xref std std-setting docutils literal notranslate\">SECRET_KEY</code></a> or\n<a class=\"reference internal\" href=\"/zh-hans/4.1/ref/settings/#std-setting-SECRET_KEY_FALLBACKS\"><code class=\"xref std std-setting docutils literal notranslate\">SECRET_KEY_FALLBACKS</code></a> can not only generate falsified session\ndata, which your site will trust, but also remotely execute arbitrary code,\nas the data is serialized using pickle.</p>\n<p>如果你使用基于 cookie 的会话，一定要注意对于任何可能远程访问的系统，密钥是完全保密的。</p>\n<p><strong>会话数据已签名但未被加密</strong></p>\n<p>当使用cookie后端时，会话数据可以被客户端读取。</p>\n<p>MAC(消息验证代码) 被用来保护数据不被客户端修改，因此会话数据在被篡改时失效。如果存储cookie 的客户端 (比如浏览器) 不能存储所有会话数据并丢弃数据，则会同样发生失效。即使 Django 压缩数据，它仍然完全有可能每个 cookie 超过4096字节的通用限制（ <span class=\"target\" id=\"index-2\"></span><a class=\"rfc reference external\" href=\"https://datatracker.ietf.org/doc/html/rfc2965.html#section-5.3\"><strong>common limit of 4096 bytes</strong></a> ）。</p>\n<p><strong>不保证新鲜度</strong></p>\n<p>注意虽然 MAC 可以保证数据(通过站点生成，而不是其他人)真实性和数据完整(它是完整和正确的)，但它不能保证新鲜度，也就是说，您最后发送给客户端的东西会被退回。这意味着cookie后端为了使用一些会话数据，可能会面临重播攻击。与其他会话后端(每个会话保持服务端记录，并且当用户退出时使会话失效)不同，基于cookie的会话在用户退出的时候并不会让会话失效。因此攻击者窃取用户cookie，即使用户登出了，攻击者还可以使用cookie登录该用户。如果 Cookie 比 <a class=\"reference internal\" href=\"/zh-hans/4.1/ref/settings/#std-setting-SESSION_COOKIE_AGE\"><code class=\"xref std std-setting docutils literal notranslate\">SESSION_COOKIE_AGE</code></a> 设置的时间还旧时，则cookie会被检测为 '陈旧' 。</p>\n<p><strong>性能</strong></p>\n<p>最后，cookie 的大小可能会对您网站的速度造成影响。</p>\n</aside>\n</section>\n</section>\n<section id=\"using-sessions-in-views\">\n<h2>在视图中使用会话<a class=\"heading-anchor\" href=\"#using-sessions-in-views\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>当激活 <code class=\"docutils literal notranslate\">SessionMiddleware</code> 后，每个 <a class=\"reference internal\" href=\"/zh-hans/4.1/ref/request-response/#django.http.HttpRequest\" title=\"django.http.HttpRequest\"><code class=\"xref py py-class docutils literal notranslate\">HttpRequest</code></a> 对象（任何 Django 视图函数的第一个参数） 将得到一个 <code class=\"docutils literal notranslate\">session</code> 属性，该属性是一个类字典对象。</p>\n<p>你可以在视图中任意位置读取它并写入 <code class=\"docutils literal notranslate\">request.session</code> 。你可以多次编辑它。</p>\n<dl class=\"py class\">\n<dt class=\"sig sig-object py\" id=\"django.contrib.sessions.backends.base.SessionBase\">\n<em class=\"property\"><span class=\"k\">class</span> </em><span class=\"sig-prename descclassname\">backends.base.</span><span class=\"sig-name descname\">SessionBase</span><a class=\"heading-anchor\" href=\"#django.contrib.sessions.backends.base.SessionBase\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>这是所有会话对象的基础类。它有以下标准字典方法：</p>\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"django.contrib.sessions.backends.base.SessionBase.__getitem__\">\n<span class=\"sig-name descname\">__getitem__</span><span class=\"sig-paren\">(</span><em class=\"sig-param\">key</em><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.contrib.sessions.backends.base.SessionBase.__getitem__\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>比如：<code class=\"docutils literal notranslate\">fav_color = request.session['fav_color']</code></p>\n</dd></dl>\n\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"django.contrib.sessions.backends.base.SessionBase.__setitem__\">\n<span class=\"sig-name descname\">__setitem__</span><span class=\"sig-paren\">(</span><em class=\"sig-param\">key</em>, <em class=\"sig-param\">value</em><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.contrib.sessions.backends.base.SessionBase.__setitem__\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>比如：<code class=\"docutils literal notranslate\">request.session['fav_color'] = 'blue'</code></p>\n</dd></dl>\n\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"django.contrib.sessions.backends.base.SessionBase.__delitem__\">\n<span class=\"sig-name descname\">__delitem__</span><span class=\"sig-paren\">(</span><em class=\"sig-param\">key</em><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.contrib.sessions.backends.base.SessionBase.__delitem__\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>比如：<code class=\"docutils literal notranslate\">del request.session['fav_color']</code> 。如果给定的 <code class=\"docutils literal notranslate\">key</code> 不在会话里，会引发 <code class=\"docutils literal notranslate\">KeyError</code> 。</p>\n</dd></dl>\n\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"django.contrib.sessions.backends.base.SessionBase.__contains__\">\n<span class=\"sig-name descname\">__contains__</span><span class=\"sig-paren\">(</span><em class=\"sig-param\">key</em><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.contrib.sessions.backends.base.SessionBase.__contains__\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>比如：<code class=\"docutils literal notranslate\">'fav_color' in request.session</code></p>\n</dd></dl>\n\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"django.contrib.sessions.backends.base.SessionBase.get\">\n<span class=\"sig-name descname\">get</span><span class=\"sig-paren\">(</span><em class=\"sig-param\">key</em>, <em class=\"sig-param\">default<span class=\"o\">=</span><span class=\"default_value\">None</span></em><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.contrib.sessions.backends.base.SessionBase.get\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>比如：<code class=\"docutils literal notranslate\">fav_color = request.session.get('fav_color', 'red')</code></p>\n</dd></dl>\n\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"django.contrib.sessions.backends.base.SessionBase.pop\">\n<span class=\"sig-name descname\">pop</span><span class=\"sig-paren\">(</span><em class=\"sig-param\">key</em>, <em class=\"sig-param\">default<span class=\"o\">=</span><span class=\"default_value\">__not_given</span></em><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.contrib.sessions.backends.base.SessionBase.pop\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>比如：<code class=\"docutils literal notranslate\">fav_color = request.session.pop('fav_color', 'blue')</code></p>\n</dd></dl>\n\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"django.contrib.sessions.backends.base.SessionBase.keys\">\n<span class=\"sig-name descname\">keys</span><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.contrib.sessions.backends.base.SessionBase.keys\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd></dd></dl>\n\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"django.contrib.sessions.backends.base.SessionBase.items\">\n<span class=\"sig-name descname\">items</span><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.contrib.sessions.backends.base.SessionBase.items\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd></dd></dl>\n\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"django.contrib.sessions.backends.base.SessionBase.setdefault\">\n<span class=\"sig-name descname\">setdefault</span><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.contrib.sessions.backends.base.SessionBase.setdefault\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd></dd></dl>\n\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"django.contrib.sessions.backends.base.SessionBase.clear\">\n<span class=\"sig-name descname\">clear</span><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.contrib.sessions.backends.base.SessionBase.clear\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd></dd></dl>\n\n<p>它也有以下方法：</p>\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"django.contrib.sessions.backends.base.SessionBase.flush\">\n<span class=\"sig-name descname\">flush</span><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.contrib.sessions.backends.base.SessionBase.flush\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>删除当前会话和会话cookie。如果你想确保早先的会话数据不能被用户的浏览器再次访问时，可以使用这个方法（比如，<a class=\"reference internal\" href=\"/zh-hans/4.1/topics/auth/default/#django.contrib.auth.logout\" title=\"django.contrib.auth.logout\"><code class=\"xref py py-func docutils literal notranslate\">django.contrib.auth.logout()</code></a> 函数调用它）。</p>\n</dd></dl>\n\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"django.contrib.sessions.backends.base.SessionBase.set_test_cookie\">\n<span class=\"sig-name descname\">set_test_cookie</span><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.contrib.sessions.backends.base.SessionBase.set_test_cookie\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>设置一个测试cookie来确定用户的浏览器是否支持cookie。由于测试通过，你不需要在下一个页面请求时再次测试它。查看 <a class=\"reference internal\" href=\"#setting-test-cookies\">Setting test cookies</a> 获取更多信息。</p>\n</dd></dl>\n\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"django.contrib.sessions.backends.base.SessionBase.test_cookie_worked\">\n<span class=\"sig-name descname\">test_cookie_worked</span><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.contrib.sessions.backends.base.SessionBase.test_cookie_worked\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>返回 <code class=\"docutils literal notranslate\">True</code> 或 <code class=\"docutils literal notranslate\">False</code> ，这取决于用户浏览器是否接受测试cookie。由于 cookie 的工作方式，你将必须在上一个独立的页面请求里调用 <code class=\"docutils literal notranslate\">set_test_cookie()</code> 。查看 <a class=\"reference internal\" href=\"#setting-test-cookies\">Setting test cookies</a> 获取更多信息。</p>\n</dd></dl>\n\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"django.contrib.sessions.backends.base.SessionBase.delete_test_cookie\">\n<span class=\"sig-name descname\">delete_test_cookie</span><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.contrib.sessions.backends.base.SessionBase.delete_test_cookie\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>删除测试cookie。使用完测试cookie后用它来删除。</p>\n</dd></dl>\n\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"django.contrib.sessions.backends.base.SessionBase.get_session_cookie_age\">\n<span class=\"sig-name descname\">get_session_cookie_age</span><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.contrib.sessions.backends.base.SessionBase.get_session_cookie_age\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>Returns the value of the setting <a class=\"reference internal\" href=\"/zh-hans/4.1/ref/settings/#std-setting-SESSION_COOKIE_AGE\"><code class=\"xref std std-setting docutils literal notranslate\">SESSION_COOKIE_AGE</code></a>. This can\nbe overridden in a custom session backend.</p>\n</dd></dl>\n\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"django.contrib.sessions.backends.base.SessionBase.set_expiry\">\n<span class=\"sig-name descname\">set_expiry</span><span class=\"sig-paren\">(</span><em class=\"sig-param\">value</em><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.contrib.sessions.backends.base.SessionBase.set_expiry\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>为会话设置过期时间。你可以传递很多不同值：</p>\n<ul class=\"simple\">\n<li><p>如果 <code class=\"docutils literal notranslate\">value</code> 是整型，会话将在闲置数秒后过期。比如，调用 <code class=\"docutils literal notranslate\">request.session.set_expiry(300)</code> 会使得会话在5分钟后过期。</p></li>\n<li><p>If <code class=\"docutils literal notranslate\">value</code> is a <code class=\"docutils literal notranslate\">datetime</code> or <code class=\"docutils literal notranslate\">timedelta</code> object, the session\nwill expire at that specific date/time.</p></li>\n<li><p>If <code class=\"docutils literal notranslate\">value</code> is <code class=\"docutils literal notranslate\">0</code>, the user's session cookie will expire\nwhen the user's web browser is closed.</p></li>\n<li><p>如果 <code class=\"docutils literal notranslate\">value</code> 是 <code class=\"docutils literal notranslate\">None</code> ，会话会恢复为全局会话过期策略。</p></li>\n</ul>\n<p>出于过期目的，读取会话不被视为活动。会话过期时间会在会话最后一次*修改*后开始计算。</p>\n</dd></dl>\n\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"django.contrib.sessions.backends.base.SessionBase.get_expiry_age\">\n<span class=\"sig-name descname\">get_expiry_age</span><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.contrib.sessions.backends.base.SessionBase.get_expiry_age\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>返回该会话过期的秒数。对于没有自定义过期时间的会话（或者那些设置为浏览器关闭时过期的），这等同于 <a class=\"reference internal\" href=\"/zh-hans/4.1/ref/settings/#std-setting-SESSION_COOKIE_AGE\"><code class=\"xref std std-setting docutils literal notranslate\">SESSION_COOKIE_AGE</code></a> 。</p>\n<p>这个函数接受两个可选的关键参数：</p>\n<ul class=\"simple\">\n<li><p><code class=\"docutils literal notranslate\">modification</code> ：会话的最后一次修改，当做一个 <a class=\"reference external\" href=\"https://docs.python.org/3/library/datetime.html#datetime.datetime\" title=\"(in Python v3.14)\"><code class=\"xref py py-class docutils literal notranslate\">datetime</code></a> 对象。默认是当前时间。</p></li>\n<li><p><code class=\"docutils literal notranslate\">expiry</code> ：会话的过期信息，如一个 <a class=\"reference external\" href=\"https://docs.python.org/3/library/datetime.html#datetime.datetime\" title=\"(in Python v3.14)\"><code class=\"xref py py-class docutils literal notranslate\">datetime</code></a> 对象，整数（秒）或 <code class=\"docutils literal notranslate\">None</code>。默认为通过 <a class=\"reference internal\" href=\"#django.contrib.sessions.backends.base.SessionBase.set_expiry\" title=\"django.contrib.sessions.backends.base.SessionBase.set_expiry\"><code class=\"xref py py-meth docutils literal notranslate\">set_expiry()</code></a> 存储在会话中的值，或 <code class=\"docutils literal notranslate\">None</code> 。</p></li>\n</ul>\n<aside class=\"admonition admonition-note\" role=\"note\">\n<p class=\"admonition-title\">Note</p>\n<p>This method is used by session backends to determine the session expiry\nage in seconds when saving the session. It is not really intended for\nusage outside of that context.</p>\n<p>In particular, while it is <strong>possible</strong> to determine the remaining\nlifetime of a session <strong>just when</strong> you have the correct\n<code class=\"docutils literal notranslate\">modification</code> value <strong>and</strong> the <code class=\"docutils literal notranslate\">expiry</code> is set as a <code class=\"docutils literal notranslate\">datetime</code>\nobject, where you do have the <code class=\"docutils literal notranslate\">modification</code> value, it is more\nstraight-forward to calculate the expiry by-hand:</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code>expires_at <span class=\"o\">=</span> modification <span class=\"o\">+</span> timedelta<span class=\"p\">(</span>seconds<span class=\"o\">=</span>settings<span class=\"o\">.</span>SESSION_COOKIE_AGE<span class=\"p\">)</span>\n</code></pre></div>\n</aside>\n</dd></dl>\n\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"django.contrib.sessions.backends.base.SessionBase.get_expiry_date\">\n<span class=\"sig-name descname\">get_expiry_date</span><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.contrib.sessions.backends.base.SessionBase.get_expiry_date\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>返回该会话的到期日期。对于没有自定义过期的会话(或那些设置为在浏览器关闭时过期的会话)，这将等于从现在开始的SESSION_COOKIE_AGE秒的日期。</p>\n<p>This function accepts the same keyword arguments as\n<a class=\"reference internal\" href=\"#django.contrib.sessions.backends.base.SessionBase.get_expiry_age\" title=\"django.contrib.sessions.backends.base.SessionBase.get_expiry_age\"><code class=\"xref py py-meth docutils literal notranslate\">get_expiry_age()</code></a>, and similar notes on usage apply.</p>\n</dd></dl>\n\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"django.contrib.sessions.backends.base.SessionBase.get_expire_at_browser_close\">\n<span class=\"sig-name descname\">get_expire_at_browser_close</span><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.contrib.sessions.backends.base.SessionBase.get_expire_at_browser_close\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>Returns either <code class=\"docutils literal notranslate\">True</code> or <code class=\"docutils literal notranslate\">False</code>, depending on whether the user's\nsession cookie will expire when the user's web browser is closed.</p>\n</dd></dl>\n\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"django.contrib.sessions.backends.base.SessionBase.clear_expired\">\n<span class=\"sig-name descname\">clear_expired</span><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.contrib.sessions.backends.base.SessionBase.clear_expired\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>从会话存储中移除过期会话。这个类方法通过 <a class=\"reference internal\" href=\"/zh-hans/4.1/ref/django-admin/#django-admin-clearsessions\"><code class=\"xref std std-djadmin docutils literal notranslate\">clearsessions</code></a> 调用。</p>\n</dd></dl>\n\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"django.contrib.sessions.backends.base.SessionBase.cycle_key\">\n<span class=\"sig-name descname\">cycle_key</span><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.contrib.sessions.backends.base.SessionBase.cycle_key\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>在保留当前会话的同时创建新的会话秘钥。<a class=\"reference internal\" href=\"/zh-hans/4.1/topics/auth/default/#django.contrib.auth.login\" title=\"django.contrib.auth.login\"><code class=\"xref py py-func docutils literal notranslate\">django.contrib.auth.login()</code></a> 调用这个方法来防止会话固定攻击。</p>\n</dd></dl>\n\n</dd></dl>\n\n<section id=\"session-serialization\">\n<span id=\"id1\"></span><h3>会话序列化<a class=\"heading-anchor\" href=\"#session-serialization\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>默认情况下，Django 序列会话数据使用 JSON 。你可以设置 <a class=\"reference internal\" href=\"/zh-hans/4.1/ref/settings/#std-setting-SESSION_SERIALIZER\"><code class=\"xref std std-setting docutils literal notranslate\">SESSION_SERIALIZER</code></a> 来自定义会话序列化格式。即使在编写你自己的序列化程序中描述了警告，我们仍然强烈建议您坚持JSON序列化，尤其是在您使用cookie后端的情况下。</p>\n<p>For example, here's an attack scenario if you use <a class=\"reference external\" href=\"https://docs.python.org/3/library/pickle.html#module-pickle\" title=\"(in Python v3.14)\"><code class=\"xref py py-mod docutils literal notranslate\">pickle</code></a> to serialize\nsession data. If you're using the <a class=\"reference internal\" href=\"#cookie-session-backend\"><span class=\"std std-ref\">signed cookie session backend</span></a> and <a class=\"reference internal\" href=\"/zh-hans/4.1/ref/settings/#std-setting-SECRET_KEY\"><code class=\"xref std std-setting docutils literal notranslate\">SECRET_KEY</code></a> (or any key of\n<a class=\"reference internal\" href=\"/zh-hans/4.1/ref/settings/#std-setting-SECRET_KEY_FALLBACKS\"><code class=\"xref std std-setting docutils literal notranslate\">SECRET_KEY_FALLBACKS</code></a>) is known by an attacker (there isn't an\ninherent vulnerability in Django that would cause it to leak), the attacker\ncould insert a string into their session which, when unpickled, executes\narbitrary code on the server. The technique for doing so is simple and easily\navailable on the internet. Although the cookie session storage signs the\ncookie-stored data to prevent tampering, a <a class=\"reference internal\" href=\"/zh-hans/4.1/ref/settings/#std-setting-SECRET_KEY\"><code class=\"xref std std-setting docutils literal notranslate\">SECRET_KEY</code></a> leak\nimmediately escalates to a remote code execution vulnerability.</p>\n<section id=\"bundled-serializers\">\n<h4>绑定序列化<a class=\"heading-anchor\" href=\"#bundled-serializers\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h4>\n<dl class=\"py class\">\n<dt class=\"sig sig-object py\" id=\"django.contrib.sessions.serializers.JSONSerializer\">\n<em class=\"property\"><span class=\"k\">class</span> </em><span class=\"sig-prename descclassname\">serializers.</span><span class=\"sig-name descname\">JSONSerializer</span><a class=\"heading-anchor\" href=\"#django.contrib.sessions.serializers.JSONSerializer\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>来自 <a class=\"reference internal\" href=\"/zh-hans/4.1/topics/signing/#module-django.core.signing\" title=\"django.core.signing: Django's signing framework.\"><code class=\"xref py py-mod docutils literal notranslate\">django.core.signing</code></a> 的JSON序列化器的装饰器。可以只序列化基本数据类型。</p>\n<p>另外，因为JSON只支持字符串键，注意在 <code class=\"docutils literal notranslate\">request.session</code> 使用非字符串键会无法工作：</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"c1\"># initial assignment</span>\n<span class=\"gp\">&gt;&gt;&gt; </span>request<span class=\"o\">.</span>session<span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"s1\">&#39;bar&#39;</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"c1\"># subsequent requests following serialization &amp; deserialization</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"c1\"># of session data</span>\n<span class=\"gp\">&gt;&gt;&gt; </span>request<span class=\"o\">.</span>session<span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]</span>  <span class=\"c1\"># KeyError</span>\n<span class=\"gp\">&gt;&gt;&gt; </span>request<span class=\"o\">.</span>session<span class=\"p\">[</span><span class=\"s1\">&#39;0&#39;</span><span class=\"p\">]</span>\n<span class=\"go\">&#39;bar&#39;</span>\n</code></pre></div>\n<p>同样，数据也不能在JSON中编码，例如像 <code class=\"docutils literal notranslate\">'\\xd9'</code> 这种非UTF8字节(会引发 <a class=\"reference external\" href=\"https://docs.python.org/3/library/exceptions.html#UnicodeDecodeError\" title=\"(in Python v3.14)\"><code class=\"xref py py-exc docutils literal notranslate\">UnicodeDecodeError</code></a> )不会被存储。</p>\n<p>查看 <a class=\"reference internal\" href=\"#custom-serializers\"><span class=\"std std-ref\">编写自定义的序列化器</span></a> 部分来获取更多有关JSON序列化局限性的内容。</p>\n</dd></dl>\n\n<dl class=\"py class\">\n<dt class=\"sig sig-object py\" id=\"django.contrib.sessions.serializers.PickleSerializer\">\n<em class=\"property\"><span class=\"k\">class</span> </em><span class=\"sig-prename descclassname\">serializers.</span><span class=\"sig-name descname\">PickleSerializer</span><a class=\"heading-anchor\" href=\"#django.contrib.sessions.serializers.PickleSerializer\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>Supports arbitrary Python objects, but, as described above, can lead to a\nremote code execution vulnerability if <a class=\"reference internal\" href=\"/zh-hans/4.1/ref/settings/#std-setting-SECRET_KEY\"><code class=\"xref std std-setting docutils literal notranslate\">SECRET_KEY</code></a> or any key of\n<a class=\"reference internal\" href=\"/zh-hans/4.1/ref/settings/#std-setting-SECRET_KEY_FALLBACKS\"><code class=\"xref std std-setting docutils literal notranslate\">SECRET_KEY_FALLBACKS</code></a> becomes known by an attacker.</p>\n<aside class=\"version-note version-deprecated\" data-version=\"4.1\" role=\"note\">\n<p class=\"version-note-title\">Deprecated since Django 4.1</p><p><span class=\"versionmodified deprecated\">Deprecated since version 4.1: </span>Due to the risk of remote code execution, this serializer is deprecated\nand will be removed in Django 5.0.</p>\n</aside>\n</dd></dl>\n\n</section>\n<section id=\"write-your-own-serializer\">\n<span id=\"custom-serializers\"></span><h4>编写自定义的序列化器<a class=\"heading-anchor\" href=\"#write-your-own-serializer\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h4>\n<p>Note that the <a class=\"reference internal\" href=\"#django.contrib.sessions.serializers.JSONSerializer\" title=\"django.contrib.sessions.serializers.JSONSerializer\"><code class=\"xref py py-class docutils literal notranslate\">JSONSerializer</code></a>\ncannot handle arbitrary Python data types. As is often the case, there is a\ntrade-off between convenience and security. If you wish to store more advanced\ndata types including <code class=\"docutils literal notranslate\">datetime</code> and <code class=\"docutils literal notranslate\">Decimal</code> in JSON backed sessions, you\nwill need to write a custom serializer (or convert such values to a JSON\nserializable object before storing them in <code class=\"docutils literal notranslate\">request.session</code>). While\nserializing these values is often straightforward\n(<a class=\"reference internal\" href=\"/zh-hans/4.1/topics/serialization/#django.core.serializers.json.DjangoJSONEncoder\" title=\"django.core.serializers.json.DjangoJSONEncoder\"><code class=\"xref py py-class docutils literal notranslate\">DjangoJSONEncoder</code></a> may be helpful),\nwriting a decoder that can reliably get back the same thing that you put in is\nmore fragile. For example, you run the risk of returning a <code class=\"docutils literal notranslate\">datetime</code> that\nwas actually a string that just happened to be in the same format chosen for\n<code class=\"docutils literal notranslate\">datetime</code>s).</p>\n<p>你的序列化类必须实现两个方法( <code class=\"docutils literal notranslate\">dumps(self, obj)</code> 和 <code class=\"docutils literal notranslate\">loads(self, data)</code> ) 来分别进行序列化和反序列化会话数据字典。</p>\n</section>\n</section>\n<section id=\"session-object-guidelines\">\n<h3>会话对象指南<a class=\"heading-anchor\" href=\"#session-object-guidelines\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<ul class=\"simple\">\n<li><p>在  <code class=\"docutils literal notranslate\">request.session</code> 上使用普通的 Python 字符串作为字典键。这更多的是一种惯例而不是硬性规定。</p></li>\n<li><p>以下划线开头的会话字典键保留给 Django 作内部使用。</p></li>\n<li><p>不要使用新对象覆盖 <code class=\"docutils literal notranslate\">request.session</code> ，不要访问或设置它的属性。像使用 Python 字典一样使用它。</p></li>\n</ul>\n</section>\n<section id=\"examples\">\n<h3>示例<a class=\"heading-anchor\" href=\"#examples\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>这个简单的视图将一个 <code class=\"docutils literal notranslate\">has_commented</code> 变量在用户评论后设置为 <code class=\"docutils literal notranslate\">True</code> 。它不允许用户发表评论多于一次：</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"k\">def</span> <span class=\"nf\">post_comment</span><span class=\"p\">(</span>request<span class=\"p\">,</span> new_comment<span class=\"p\">):</span>\n    <span class=\"k\">if</span> request<span class=\"o\">.</span>session<span class=\"o\">.</span>get<span class=\"p\">(</span><span class=\"s1\">&#39;has_commented&#39;</span><span class=\"p\">,</span> <span class=\"kc\">False</span><span class=\"p\">):</span>\n        <span class=\"k\">return</span> HttpResponse<span class=\"p\">(</span><span class=\"s2\">&quot;You&#39;ve already commented.&quot;</span><span class=\"p\">)</span>\n    c <span class=\"o\">=</span> comments<span class=\"o\">.</span>Comment<span class=\"p\">(</span>comment<span class=\"o\">=</span>new_comment<span class=\"p\">)</span>\n    c<span class=\"o\">.</span>save<span class=\"p\">()</span>\n    request<span class=\"o\">.</span>session<span class=\"p\">[</span><span class=\"s1\">&#39;has_commented&#39;</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"kc\">True</span>\n    <span class=\"k\">return</span> HttpResponse<span class=\"p\">(</span><span class=\"s1\">&#39;Thanks for your comment!&#39;</span><span class=\"p\">)</span>\n</code></pre></div>\n<p>这是一个记录站点成员的简单的视图。</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"k\">def</span> <span class=\"nf\">login</span><span class=\"p\">(</span>request<span class=\"p\">):</span>\n    m <span class=\"o\">=</span> Member<span class=\"o\">.</span>objects<span class=\"o\">.</span>get<span class=\"p\">(</span>username<span class=\"o\">=</span>request<span class=\"o\">.</span>POST<span class=\"p\">[</span><span class=\"s1\">&#39;username&#39;</span><span class=\"p\">])</span>\n    <span class=\"k\">if</span> m<span class=\"o\">.</span>check_password<span class=\"p\">(</span>request<span class=\"o\">.</span>POST<span class=\"p\">[</span><span class=\"s1\">&#39;password&#39;</span><span class=\"p\">]):</span>\n        request<span class=\"o\">.</span>session<span class=\"p\">[</span><span class=\"s1\">&#39;member_id&#39;</span><span class=\"p\">]</span> <span class=\"o\">=</span> m<span class=\"o\">.</span>id\n        <span class=\"k\">return</span> HttpResponse<span class=\"p\">(</span><span class=\"s2\">&quot;You&#39;re logged in.&quot;</span><span class=\"p\">)</span>\n    <span class=\"k\">else</span><span class=\"p\">:</span>\n        <span class=\"k\">return</span> HttpResponse<span class=\"p\">(</span><span class=\"s2\">&quot;Your username and password didn&#39;t match.&quot;</span><span class=\"p\">)</span>\n</code></pre></div>\n<p>这是记录成员退出的视图：</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"k\">def</span> <span class=\"nf\">logout</span><span class=\"p\">(</span>request<span class=\"p\">):</span>\n    <span class=\"k\">try</span><span class=\"p\">:</span>\n        <span class=\"k\">del</span> request<span class=\"o\">.</span>session<span class=\"p\">[</span><span class=\"s1\">&#39;member_id&#39;</span><span class=\"p\">]</span>\n    <span class=\"k\">except</span> <span class=\"ne\">KeyError</span><span class=\"p\">:</span>\n        <span class=\"k\">pass</span>\n    <span class=\"k\">return</span> HttpResponse<span class=\"p\">(</span><span class=\"s2\">&quot;You&#39;re logged out.&quot;</span><span class=\"p\">)</span>\n</code></pre></div>\n<p>标准的 <a class=\"reference internal\" href=\"/zh-hans/4.1/topics/auth/default/#django.contrib.auth.logout\" title=\"django.contrib.auth.logout\"><code class=\"xref py py-meth docutils literal notranslate\">django.contrib.auth.logout()</code></a> 函数实际上比这里要多一些来防止数据意外泄露。它调用 <code class=\"docutils literal notranslate\">request.session</code> 的 <a class=\"reference internal\" href=\"#django.contrib.sessions.backends.base.SessionBase.flush\" title=\"django.contrib.sessions.backends.base.SessionBase.flush\"><code class=\"xref py py-meth docutils literal notranslate\">flush()</code></a> 方法。我们使用这个例子作为示范如何使用会话对象，而不是完整的 <code class=\"docutils literal notranslate\">logout()</code> 实现。</p>\n</section>\n</section>\n<section id=\"setting-test-cookies\">\n<h2>测试 <code class=\"docutils literal notranslate\">cookies</code> 设置<a class=\"heading-anchor\" href=\"#setting-test-cookies\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>为了方便起见，Django 提供一种方法来测试用户浏览器是否支持cookies。调用视图里 <code class=\"docutils literal notranslate\">request.session</code> 的 <a class=\"reference internal\" href=\"#django.contrib.sessions.backends.base.SessionBase.set_test_cookie\" title=\"django.contrib.sessions.backends.base.SessionBase.set_test_cookie\"><code class=\"xref py py-meth docutils literal notranslate\">set_test_cookie()</code></a> 方法，并且在后续视图里调用 <a class=\"reference internal\" href=\"#django.contrib.sessions.backends.base.SessionBase.test_cookie_worked\" title=\"django.contrib.sessions.backends.base.SessionBase.test_cookie_worked\"><code class=\"xref py py-meth docutils literal notranslate\">test_cookie_worked()</code></a> —— 不是在同一个视图里调用。</p>\n<p>由于 cookies 的工作方式， <code class=\"docutils literal notranslate\">set_test_cookie()</code> 和 <code class=\"docutils literal notranslate\">test_cookie_worked()</code> 之间尴尬的分割是有必要的。当你设置了一个 cookie，在浏览器的下一个请求之前，实际上你不能判断浏览器是否接受它。</p>\n<p>使用 <a class=\"reference internal\" href=\"#django.contrib.sessions.backends.base.SessionBase.delete_test_cookie\" title=\"django.contrib.sessions.backends.base.SessionBase.delete_test_cookie\"><code class=\"xref py py-meth docutils literal notranslate\">delete_test_cookie()</code></a> 来清理是个好习惯。在验证测试的 cookie 可用之后来执行它。</p>\n<p>这里是一个典型的用法示例：</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"kn\">from</span> <span class=\"nn\">django.http</span> <span class=\"kn\">import</span> HttpResponse\n<span class=\"kn\">from</span> <span class=\"nn\">django.shortcuts</span> <span class=\"kn\">import</span> render\n\n<span class=\"k\">def</span> <span class=\"nf\">login</span><span class=\"p\">(</span>request<span class=\"p\">):</span>\n    <span class=\"k\">if</span> request<span class=\"o\">.</span>method <span class=\"o\">==</span> <span class=\"s1\">&#39;POST&#39;</span><span class=\"p\">:</span>\n        <span class=\"k\">if</span> request<span class=\"o\">.</span>session<span class=\"o\">.</span>test_cookie_worked<span class=\"p\">():</span>\n            request<span class=\"o\">.</span>session<span class=\"o\">.</span>delete_test_cookie<span class=\"p\">()</span>\n            <span class=\"k\">return</span> HttpResponse<span class=\"p\">(</span><span class=\"s2\">&quot;You&#39;re logged in.&quot;</span><span class=\"p\">)</span>\n        <span class=\"k\">else</span><span class=\"p\">:</span>\n            <span class=\"k\">return</span> HttpResponse<span class=\"p\">(</span><span class=\"s2\">&quot;Please enable cookies and try again.&quot;</span><span class=\"p\">)</span>\n    request<span class=\"o\">.</span>session<span class=\"o\">.</span>set_test_cookie<span class=\"p\">()</span>\n    <span class=\"k\">return</span> render<span class=\"p\">(</span>request<span class=\"p\">,</span> <span class=\"s1\">&#39;foo/login_form.html&#39;</span><span class=\"p\">)</span>\n</code></pre></div>\n</section>\n<section id=\"using-sessions-out-of-views\">\n<h2>在视图外使用会话<a class=\"heading-anchor\" href=\"#using-sessions-out-of-views\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<aside class=\"admonition admonition-note\" role=\"note\">\n<p class=\"admonition-title\">Note</p>\n<p>这部分的例子直接从 <code class=\"docutils literal notranslate\">django.contrib.sessions.backends.db</code> 后端导入 <code class=\"docutils literal notranslate\">SessionStore</code> 对象。在你自己的代码里，你应该考虑从 <a class=\"reference internal\" href=\"/zh-hans/4.1/ref/settings/#std-setting-SESSION_ENGINE\"><code class=\"xref std std-setting docutils literal notranslate\">SESSION_ENGINE</code></a> 指定的会话引擎导入 <code class=\"docutils literal notranslate\">SessionStore</code> 。</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"kn\">from</span> <span class=\"nn\">importlib</span> <span class=\"kn\">import</span> import_module\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"kn\">from</span> <span class=\"nn\">django.conf</span> <span class=\"kn\">import</span> settings\n<span class=\"gp\">&gt;&gt;&gt; </span>SessionStore <span class=\"o\">=</span> import_module<span class=\"p\">(</span>settings<span class=\"o\">.</span>SESSION_ENGINE<span class=\"p\">)</span><span class=\"o\">.</span>SessionStore\n</code></pre></div>\n</aside>\n<p>可以在视图外对会话数据进行操作的 API ：</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"kn\">from</span> <span class=\"nn\">django.contrib.sessions.backends.db</span> <span class=\"kn\">import</span> SessionStore\n<span class=\"gp\">&gt;&gt;&gt; </span>s <span class=\"o\">=</span> SessionStore<span class=\"p\">()</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"c1\"># stored as seconds since epoch since datetimes are not serializable in JSON.</span>\n<span class=\"gp\">&gt;&gt;&gt; </span>s<span class=\"p\">[</span><span class=\"s1\">&#39;last_login&#39;</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"mi\">1376587691</span>\n<span class=\"gp\">&gt;&gt;&gt; </span>s<span class=\"o\">.</span>create<span class=\"p\">()</span>\n<span class=\"gp\">&gt;&gt;&gt; </span>s<span class=\"o\">.</span>session_key\n<span class=\"go\">&#39;2b1189a188b44ad18c35e113ac6ceead&#39;</span>\n<span class=\"gp\">&gt;&gt;&gt; </span>s <span class=\"o\">=</span> SessionStore<span class=\"p\">(</span>session_key<span class=\"o\">=</span><span class=\"s1\">&#39;2b1189a188b44ad18c35e113ac6ceead&#39;</span><span class=\"p\">)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span>s<span class=\"p\">[</span><span class=\"s1\">&#39;last_login&#39;</span><span class=\"p\">]</span>\n<span class=\"go\">1376587691</span>\n</code></pre></div>\n<p><code class=\"docutils literal notranslate\">SessionStore.create()</code> 用来创建一个新会话（即不从会话中加载，并带有 <code class=\"docutils literal notranslate\">session_key=None</code>）。<code class=\"docutils literal notranslate\">save()</code> 用来保存已存在的会话（即从会话存储中加载）。在新会话上调用 <code class=\"docutils literal notranslate\">save()</code> 也许会工作，但生成与现有会话相冲突的 <code class=\"docutils literal notranslate\">session_key</code> 的概率很小。<code class=\"docutils literal notranslate\">create()</code> 调用 <code class=\"docutils literal notranslate\">save()</code> 并循环，直到生成了未使用过的 <code class=\"docutils literal notranslate\">session_key</code> 。</p>\n<p>如果你正在使用 <code class=\"docutils literal notranslate\">django.contrib.sessions.backends.db</code> 后端，每个会话就会是一个普通的 Django 模型。 <code class=\"docutils literal notranslate\">Session</code> 模型在 <code class=\"docutils literal notranslate\">django/contrib/sessions/models.py</code> 中定义。因为它就是一个普通模型，你可以使用普通的 Django 数据库 API 访问会话。</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"kn\">from</span> <span class=\"nn\">django.contrib.sessions.models</span> <span class=\"kn\">import</span> Session\n<span class=\"gp\">&gt;&gt;&gt; </span>s <span class=\"o\">=</span> Session<span class=\"o\">.</span>objects<span class=\"o\">.</span>get<span class=\"p\">(</span>pk<span class=\"o\">=</span><span class=\"s1\">&#39;2b1189a188b44ad18c35e113ac6ceead&#39;</span><span class=\"p\">)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span>s<span class=\"o\">.</span>expire_date\n<span class=\"go\">datetime.datetime(2005, 8, 20, 13, 35, 12)</span>\n</code></pre></div>\n<p>注意你将需要调用 <a class=\"reference internal\" href=\"#django.contrib.sessions.base_session.AbstractBaseSession.get_decoded\" title=\"django.contrib.sessions.base_session.AbstractBaseSession.get_decoded\"><code class=\"xref py py-meth docutils literal notranslate\">get_decoded()</code></a> 来得到会话字典。这是必须的，因为字典是按照编码格式存储的：</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"gp\">&gt;&gt;&gt; </span>s<span class=\"o\">.</span>session_data\n<span class=\"go\">&#39;KGRwMQpTJ19hdXRoX3VzZXJfaWQnCnAyCkkxCnMuMTExY2ZjODI2Yj...&#39;</span>\n<span class=\"gp\">&gt;&gt;&gt; </span>s<span class=\"o\">.</span>get_decoded<span class=\"p\">()</span>\n<span class=\"go\">{&#39;user_id&#39;: 42}</span>\n</code></pre></div>\n</section>\n<section id=\"when-sessions-are-saved\">\n<h2>当保存会话时<a class=\"heading-anchor\" href=\"#when-sessions-are-saved\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>默认情况下，Django 只在会话被修改后才会向会话数据库保存会话——也就是说，是否已经分配或删除了它的任何字典值：</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"c1\"># Session is modified.</span>\nrequest<span class=\"o\">.</span>session<span class=\"p\">[</span><span class=\"s1\">&#39;foo&#39;</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"s1\">&#39;bar&#39;</span>\n\n<span class=\"c1\"># Session is modified.</span>\n<span class=\"k\">del</span> request<span class=\"o\">.</span>session<span class=\"p\">[</span><span class=\"s1\">&#39;foo&#39;</span><span class=\"p\">]</span>\n\n<span class=\"c1\"># Session is modified.</span>\nrequest<span class=\"o\">.</span>session<span class=\"p\">[</span><span class=\"s1\">&#39;foo&#39;</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"p\">{}</span>\n\n<span class=\"c1\"># Gotcha: Session is NOT modified, because this alters</span>\n<span class=\"c1\"># request.session[&#39;foo&#39;] instead of request.session.</span>\nrequest<span class=\"o\">.</span>session<span class=\"p\">[</span><span class=\"s1\">&#39;foo&#39;</span><span class=\"p\">][</span><span class=\"s1\">&#39;bar&#39;</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"s1\">&#39;baz&#39;</span>\n</code></pre></div>\n<p>在上面例子的最后一个例子中，我们可以通过在会话对象上设置 <code class=\"docutils literal notranslate\">modified</code> 属性来明确地告诉会话对象它已经被修改：</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code>request<span class=\"o\">.</span>session<span class=\"o\">.</span>modified <span class=\"o\">=</span> <span class=\"kc\">True</span>\n</code></pre></div>\n<p>要想改变这个默认行为，可以设置 <a class=\"reference internal\" href=\"/zh-hans/4.1/ref/settings/#std-setting-SESSION_SAVE_EVERY_REQUEST\"><code class=\"xref std std-setting docutils literal notranslate\">SESSION_SAVE_EVERY_REQUEST</code></a> 为 <code class=\"docutils literal notranslate\">True</code> 。当设置为 <code class=\"docutils literal notranslate\">True</code> 时，Django 会根据每个请求将会话保存到数据库中。</p>\n<p>注意，仅在会话被创建或修改时发送会话 cookie 。如果 <a class=\"reference internal\" href=\"/zh-hans/4.1/ref/settings/#std-setting-SESSION_SAVE_EVERY_REQUEST\"><code class=\"xref std std-setting docutils literal notranslate\">SESSION_SAVE_EVERY_REQUEST</code></a> 为 <code class=\"docutils literal notranslate\">True</code> ，则会话cookie将在每次请求时发送。</p>\n<p>同样地，每次发送会话 cookie 时都会更新会话 cookie 的 <code class=\"docutils literal notranslate\">expires</code> 部分。</p>\n<p>如果响应状态代码为 500，会话不会被保存。</p>\n</section>\n<section id=\"browser-length-sessions-vs-persistent-sessions\">\n<span id=\"browser-length-vs-persistent-sessions\"></span><h2>Browser-length 会话 vs 持久会话<a class=\"heading-anchor\" href=\"#browser-length-sessions-vs-persistent-sessions\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>你可以通过设置 <a class=\"reference internal\" href=\"/zh-hans/4.1/ref/settings/#std-setting-SESSION_EXPIRE_AT_BROWSER_CLOSE\"><code class=\"xref std std-setting docutils literal notranslate\">SESSION_EXPIRE_AT_BROWSER_CLOSE</code></a> 来控制会话框架是使用 browser-length 会话还是持久会话。</p>\n<p>默认情况下， <a class=\"reference internal\" href=\"/zh-hans/4.1/ref/settings/#std-setting-SESSION_EXPIRE_AT_BROWSER_CLOSE\"><code class=\"xref std std-setting docutils literal notranslate\">SESSION_EXPIRE_AT_BROWSER_CLOSE</code></a> 为 <code class=\"docutils literal notranslate\">False</code> ，这意味着会话 cookies 将保存在用户浏览器中持续 <a class=\"reference internal\" href=\"/zh-hans/4.1/ref/settings/#std-setting-SESSION_COOKIE_AGE\"><code class=\"xref std std-setting docutils literal notranslate\">SESSION_COOKIE_AGE</code></a> 的时间。如果你不想用户每次打开浏览器时必须登录，就用这个。</p>\n<p>如果 <a class=\"reference internal\" href=\"/zh-hans/4.1/ref/settings/#std-setting-SESSION_EXPIRE_AT_BROWSER_CLOSE\"><code class=\"xref std std-setting docutils literal notranslate\">SESSION_EXPIRE_AT_BROWSER_CLOSE</code></a> 为 <code class=\"docutils literal notranslate\">True</code>，Django 将使用 browser-length cookies —— cookies 在用户关闭浏览器时过期。如果你想让用户每次打开浏览器时必须登录，就用这个。</p>\n<p>这个设置是全局默认的，并且可以通过显式调用 <code class=\"docutils literal notranslate\">request.session</code>  的 <a class=\"reference internal\" href=\"#django.contrib.sessions.backends.base.SessionBase.set_expiry\" title=\"django.contrib.sessions.backends.base.SessionBase.set_expiry\"><code class=\"xref py py-meth docutils literal notranslate\">set_expiry()</code></a> 在每个会话级别上覆盖，和之前的 <a class=\"reference internal\" href=\"#using-sessions-in-views\">using sessions in views</a> 里描述的一样。</p>\n<aside class=\"admonition admonition-note\" role=\"note\">\n<p class=\"admonition-title\">Note</p>\n<p>Some browsers (Chrome, for example) provide settings that allow users to\ncontinue browsing sessions after closing and reopening the browser. In\nsome cases, this can interfere with the\n<a class=\"reference internal\" href=\"/zh-hans/4.1/ref/settings/#std-setting-SESSION_EXPIRE_AT_BROWSER_CLOSE\"><code class=\"xref std std-setting docutils literal notranslate\">SESSION_EXPIRE_AT_BROWSER_CLOSE</code></a> setting and prevent sessions\nfrom expiring on browser close. Please be aware of this while testing\nDjango applications which have the\n<a class=\"reference internal\" href=\"/zh-hans/4.1/ref/settings/#std-setting-SESSION_EXPIRE_AT_BROWSER_CLOSE\"><code class=\"xref std std-setting docutils literal notranslate\">SESSION_EXPIRE_AT_BROWSER_CLOSE</code></a> setting enabled.</p>\n</aside>\n</section>\n<section id=\"clearing-the-session-store\">\n<span id=\"id2\"></span><h2>清除会话存储<a class=\"heading-anchor\" href=\"#clearing-the-session-store\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>当用户创建了新会话，会话数据会累积在会话存储中。如果你正在使用数据库后端，<code class=\"docutils literal notranslate\">django_session</code> 数据库表会增加。如果你使用的是文件后端，临时目录会包含新增加的文件。</p>\n<p>为了理解这个问题，要考虑数据库后端会发生什么。当用户登录时，Django 在 <code class=\"docutils literal notranslate\">django_session</code> 增加了一行。每次会话更改时，Django 会更新该行。如果用户手动退出，Django 会删除该行。但如果用户不退出，该行就不会被删除。文件后端也是类似的处理。</p>\n<p>Django 没有提供过期会话自动清除的功能。因此，你需要定期清除过期会话。Django 提供了一个清除管理命令：<a class=\"reference internal\" href=\"/zh-hans/4.1/ref/django-admin/#django-admin-clearsessions\"><code class=\"xref std std-djadmin docutils literal notranslate\">clearsessions</code></a> 。推荐在定期清除时使用该命令，例如在日常的定时任务中。</p>\n<p>注意缓存后端不受此问题的影响，因为缓存会自动删除过期数据。cookie 后端也一样，因为会话数据通过浏览器存储。</p>\n</section>\n<section id=\"settings\">\n<h2>配置<a class=\"heading-anchor\" href=\"#settings\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>一些可以用来控制会话行为的 <a class=\"reference internal\" href=\"/zh-hans/4.1/ref/settings/#settings-sessions\"><span class=\"std std-ref\">Django settings</span></a> ：</p>\n<ul class=\"simple\">\n<li><p><a class=\"reference internal\" href=\"/zh-hans/4.1/ref/settings/#std-setting-SESSION_CACHE_ALIAS\"><code class=\"xref std std-setting docutils literal notranslate\">SESSION_CACHE_ALIAS</code></a></p></li>\n<li><p><a class=\"reference internal\" href=\"/zh-hans/4.1/ref/settings/#std-setting-SESSION_COOKIE_AGE\"><code class=\"xref std std-setting docutils literal notranslate\">SESSION_COOKIE_AGE</code></a></p></li>\n<li><p><a class=\"reference internal\" href=\"/zh-hans/4.1/ref/settings/#std-setting-SESSION_COOKIE_DOMAIN\"><code class=\"xref std std-setting docutils literal notranslate\">SESSION_COOKIE_DOMAIN</code></a></p></li>\n<li><p><a class=\"reference internal\" href=\"/zh-hans/4.1/ref/settings/#std-setting-SESSION_COOKIE_HTTPONLY\"><code class=\"xref std std-setting docutils literal notranslate\">SESSION_COOKIE_HTTPONLY</code></a></p></li>\n<li><p><a class=\"reference internal\" href=\"/zh-hans/4.1/ref/settings/#std-setting-SESSION_COOKIE_NAME\"><code class=\"xref std std-setting docutils literal notranslate\">SESSION_COOKIE_NAME</code></a></p></li>\n<li><p><a class=\"reference internal\" href=\"/zh-hans/4.1/ref/settings/#std-setting-SESSION_COOKIE_PATH\"><code class=\"xref std std-setting docutils literal notranslate\">SESSION_COOKIE_PATH</code></a></p></li>\n<li><p><a class=\"reference internal\" href=\"/zh-hans/4.1/ref/settings/#std-setting-SESSION_COOKIE_SAMESITE\"><code class=\"xref std std-setting docutils literal notranslate\">SESSION_COOKIE_SAMESITE</code></a></p></li>\n<li><p><a class=\"reference internal\" href=\"/zh-hans/4.1/ref/settings/#std-setting-SESSION_COOKIE_SECURE\"><code class=\"xref std std-setting docutils literal notranslate\">SESSION_COOKIE_SECURE</code></a></p></li>\n<li><p><a class=\"reference internal\" href=\"/zh-hans/4.1/ref/settings/#std-setting-SESSION_ENGINE\"><code class=\"xref std std-setting docutils literal notranslate\">SESSION_ENGINE</code></a></p></li>\n<li><p><a class=\"reference internal\" href=\"/zh-hans/4.1/ref/settings/#std-setting-SESSION_EXPIRE_AT_BROWSER_CLOSE\"><code class=\"xref std std-setting docutils literal notranslate\">SESSION_EXPIRE_AT_BROWSER_CLOSE</code></a></p></li>\n<li><p><a class=\"reference internal\" href=\"/zh-hans/4.1/ref/settings/#std-setting-SESSION_FILE_PATH\"><code class=\"xref std std-setting docutils literal notranslate\">SESSION_FILE_PATH</code></a></p></li>\n<li><p><a class=\"reference internal\" href=\"/zh-hans/4.1/ref/settings/#std-setting-SESSION_SAVE_EVERY_REQUEST\"><code class=\"xref std std-setting docutils literal notranslate\">SESSION_SAVE_EVERY_REQUEST</code></a></p></li>\n<li><p><a class=\"reference internal\" href=\"/zh-hans/4.1/ref/settings/#std-setting-SESSION_SERIALIZER\"><code class=\"xref std std-setting docutils literal notranslate\">SESSION_SERIALIZER</code></a></p></li>\n</ul>\n</section>\n<section id=\"session-security\">\n<span id=\"topics-session-security\"></span><h2>会话安全<a class=\"heading-anchor\" href=\"#session-security\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>站点内的子域可以在客户端上为整个域设置 cookies。如果 cookies 允许来自不受新人用户控制的子域，这将使会话固定成为可能。</p>\n<p>比如，一个攻击者登入了 <code class=\"docutils literal notranslate\">good.example.com</code> 并且为账户获得了一个有效会话。如果攻击者控制了 <code class=\"docutils literal notranslate\">bad.example.com</code> ，他们可以使用它来发送他们的会话秘钥给你（会话秘钥是保证用户跟其它计算机或者两台计算机之间安全通信会话而随机产生的加密和解密密钥），因为子域已经允许在 <code class=\"docutils literal notranslate\">*.example.com</code> 上设置 cookies 。</p>\n<p>另一个可能的攻击是如果 <code class=\"docutils literal notranslate\">good.example.com</code> 设置它的 <a class=\"reference internal\" href=\"/zh-hans/4.1/ref/settings/#std-setting-SESSION_COOKIE_DOMAIN\"><code class=\"xref std std-setting docutils literal notranslate\">SESSION_COOKIE_DOMAIN</code></a> 为 <code class=\"docutils literal notranslate\">&quot;example.com&quot;</code> ，会导致来自站点的会话 cookies 发送到 <code class=\"docutils literal notranslate\">bad.example.com</code> 。</p>\n</section>\n<section id=\"technical-details\">\n<h2>技术细节<a class=\"heading-anchor\" href=\"#technical-details\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<ul class=\"simple\">\n<li><p>The session dictionary accepts any <a class=\"reference external\" href=\"https://docs.python.org/3/library/json.html#module-json\" title=\"(in Python v3.14)\"><code class=\"xref py py-mod docutils literal notranslate\">json</code></a> serializable value when using\n<a class=\"reference internal\" href=\"#django.contrib.sessions.serializers.JSONSerializer\" title=\"django.contrib.sessions.serializers.JSONSerializer\"><code class=\"xref py py-class docutils literal notranslate\">JSONSerializer</code></a>.</p></li>\n<li><p>会话数据保存在名为 <code class=\"docutils literal notranslate\">django_session</code> 的数据库表中。</p></li>\n<li><p>Django 只有它需要的时候才会发送 cookie 。如果你不想设置任何会话数据，它将不会发送会话 cookie 。</p></li>\n</ul>\n<section id=\"the-sessionstore-object\">\n<h3><code class=\"docutils literal notranslate\">SessionStore</code> 对象<a class=\"heading-anchor\" href=\"#the-sessionstore-object\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>当内部使用会话时，Django 使用来自相应会话引擎的会话存储对象。按照惯例，会话存储对象类名为 <code class=\"docutils literal notranslate\">SessionStore</code> ，并且位于 <a class=\"reference internal\" href=\"/zh-hans/4.1/ref/settings/#std-setting-SESSION_ENGINE\"><code class=\"xref std std-setting docutils literal notranslate\">SESSION_ENGINE</code></a> 的模块中。</p>\n<p>所有 <code class=\"docutils literal notranslate\">SessionStore</code> 类继承了 <a class=\"reference internal\" href=\"#django.contrib.sessions.backends.base.SessionBase\" title=\"django.contrib.sessions.backends.base.SessionBase\"><code class=\"xref py py-class docutils literal notranslate\">SessionBase</code></a> 并且实现了数据操作方法，即：</p>\n<ul class=\"simple\">\n<li><p><code class=\"docutils literal notranslate\">exists()</code></p></li>\n<li><p><code class=\"docutils literal notranslate\">create()</code></p></li>\n<li><p><code class=\"docutils literal notranslate\">save()</code></p></li>\n<li><p><code class=\"docutils literal notranslate\">delete()</code></p></li>\n<li><p><code class=\"docutils literal notranslate\">load()</code></p></li>\n<li><p><a class=\"reference internal\" href=\"#django.contrib.sessions.backends.base.SessionBase.clear_expired\" title=\"django.contrib.sessions.backends.base.SessionBase.clear_expired\"><code class=\"xref py py-meth docutils literal notranslate\">clear_expired()</code></a></p></li>\n</ul>\n<p>为了搭建自定义的会话引擎或自定义已有的引擎，你可以创建一个继承自 <a class=\"reference internal\" href=\"#django.contrib.sessions.backends.base.SessionBase\" title=\"django.contrib.sessions.backends.base.SessionBase\"><code class=\"xref py py-class docutils literal notranslate\">SessionBase</code></a> 的新类或任何其他已存在的 <code class=\"docutils literal notranslate\">SessionStore</code> 类。</p>\n<p>你可以扩展会话引擎，但对于使用数据库支持的会话引擎通常需要额外的功夫（查看下节来获取更多详情）。</p>\n</section>\n</section>\n<section id=\"extending-database-backed-session-engines\">\n<span id=\"id3\"></span><h2>扩展数据库支持的会话引擎<a class=\"heading-anchor\" href=\"#extending-database-backed-session-engines\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>可以通过继承 <a class=\"reference internal\" href=\"#django.contrib.sessions.base_session.AbstractBaseSession\" title=\"django.contrib.sessions.base_session.AbstractBaseSession\"><code class=\"xref py py-class docutils literal notranslate\">AbstractBaseSession</code></a> 和 <code class=\"docutils literal notranslate\">SessionStore``类来创建基于Django中包含的自定义数据库支持的会话引擎(即 ``db</code> 和 <code class=\"docutils literal notranslate\">cached_db</code> )。</p>\n<p><code class=\"docutils literal notranslate\">AbstractBaseSession</code> 和 <code class=\"docutils literal notranslate\">BaseSessionManager</code> 可以从 <code class=\"docutils literal notranslate\">django.contrib.sessions.base_session</code> 导入，因此它们可以在  <a class=\"reference internal\" href=\"/zh-hans/4.1/ref/settings/#std-setting-INSTALLED_APPS\"><code class=\"xref std std-setting docutils literal notranslate\">INSTALLED_APPS</code></a> 不包含 <code class=\"docutils literal notranslate\">django.contrib.sessions</code> 的情况下导入。</p>\n<dl class=\"py class\">\n<dt class=\"sig sig-object py\" id=\"django.contrib.sessions.base_session.AbstractBaseSession\">\n<em class=\"property\"><span class=\"k\">class</span> </em><span class=\"sig-prename descclassname\">base_session.</span><span class=\"sig-name descname\">AbstractBaseSession</span><a class=\"heading-anchor\" href=\"#django.contrib.sessions.base_session.AbstractBaseSession\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>抽象基本会话模型。</p>\n<dl class=\"py attribute\">\n<dt class=\"sig sig-object py\" id=\"django.contrib.sessions.base_session.AbstractBaseSession.session_key\">\n<span class=\"sig-name descname\">session_key</span><a class=\"heading-anchor\" href=\"#django.contrib.sessions.base_session.AbstractBaseSession.session_key\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>主键。字段本身可能包含多达40个字符。当前实现生成一个32个字符的字符串（一个随机的数字序列和小写的ascii字母）。</p>\n</dd></dl>\n\n<dl class=\"py attribute\">\n<dt class=\"sig sig-object py\" id=\"django.contrib.sessions.base_session.AbstractBaseSession.session_data\">\n<span class=\"sig-name descname\">session_data</span><a class=\"heading-anchor\" href=\"#django.contrib.sessions.base_session.AbstractBaseSession.session_data\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>包含编码和序列化会话字典的字符串。</p>\n</dd></dl>\n\n<dl class=\"py attribute\">\n<dt class=\"sig sig-object py\" id=\"django.contrib.sessions.base_session.AbstractBaseSession.expire_date\">\n<span class=\"sig-name descname\">expire_date</span><a class=\"heading-anchor\" href=\"#django.contrib.sessions.base_session.AbstractBaseSession.expire_date\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>指定会话何时到期的日期时间。</p>\n<p>但是，过期的会话对用户不可用，但在运行 <a class=\"reference internal\" href=\"/zh-hans/4.1/ref/django-admin/#django-admin-clearsessions\"><code class=\"xref std std-djadmin docutils literal notranslate\">clearsessions</code></a> 管理命令之前，它们仍可能存储在数据库中。</p>\n</dd></dl>\n\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"django.contrib.sessions.base_session.AbstractBaseSession.get_session_store_class\">\n<em class=\"property\"><span class=\"k\">classmethod</span> </em><span class=\"sig-name descname\">get_session_store_class</span><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.contrib.sessions.base_session.AbstractBaseSession.get_session_store_class\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>返回要与此会话模型一起使用的会话存储类。</p>\n</dd></dl>\n\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"django.contrib.sessions.base_session.AbstractBaseSession.get_decoded\">\n<span class=\"sig-name descname\">get_decoded</span><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.contrib.sessions.base_session.AbstractBaseSession.get_decoded\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>返回解码的会话数据。</p>\n<p>解码由会话存储类执行。</p>\n</dd></dl>\n\n</dd></dl>\n\n<p>还可以通过子类 <a class=\"reference internal\" href=\"#django.contrib.sessions.base_session.BaseSessionManager\" title=\"django.contrib.sessions.base_session.BaseSessionManager\"><code class=\"xref py py-class docutils literal notranslate\">BaseSessionManager</code></a> 自定义模型管理器。</p>\n<dl class=\"py class\">\n<dt class=\"sig sig-object py\" id=\"django.contrib.sessions.base_session.BaseSessionManager\">\n<em class=\"property\"><span class=\"k\">class</span> </em><span class=\"sig-prename descclassname\">base_session.</span><span class=\"sig-name descname\">BaseSessionManager</span><a class=\"heading-anchor\" href=\"#django.contrib.sessions.base_session.BaseSessionManager\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"django.contrib.sessions.base_session.BaseSessionManager.encode\">\n<span class=\"sig-name descname\">encode</span><span class=\"sig-paren\">(</span><em class=\"sig-param\">session_dict</em><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.contrib.sessions.base_session.BaseSessionManager.encode\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>返回序列化并编码为字符串的给定会话字典。</p>\n<p>编码由绑定到模型类的会话存储类执行。</p>\n</dd></dl>\n\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"django.contrib.sessions.base_session.BaseSessionManager.save\">\n<span class=\"sig-name descname\">save</span><span class=\"sig-paren\">(</span><em class=\"sig-param\">session_key</em>, <em class=\"sig-param\">session_dict</em>, <em class=\"sig-param\">expire_date</em><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.contrib.sessions.base_session.BaseSessionManager.save\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>为提供的会话密钥保存会话数据，或在数据为空时删除会话。</p>\n</dd></dl>\n\n</dd></dl>\n\n<p>通过重写以下描述的方法和属性，实现了 <code class=\"docutils literal notranslate\">SessionStore</code> 类的定制：</p>\n<dl class=\"py class\">\n<dt class=\"sig sig-object py\" id=\"django.contrib.sessions.backends.db.SessionStore\">\n<em class=\"property\"><span class=\"k\">class</span> </em><span class=\"sig-prename descclassname\">backends.db.</span><span class=\"sig-name descname\">SessionStore</span><a class=\"heading-anchor\" href=\"#django.contrib.sessions.backends.db.SessionStore\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>实现数据库支持的会话存储。</p>\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"django.contrib.sessions.backends.db.SessionStore.get_model_class\">\n<em class=\"property\"><span class=\"k\">classmethod</span> </em><span class=\"sig-name descname\">get_model_class</span><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.contrib.sessions.backends.db.SessionStore.get_model_class\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>如果需要的话，重写此方法以返回自定义会话模型。</p>\n</dd></dl>\n\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"django.contrib.sessions.backends.db.SessionStore.create_model_instance\">\n<span class=\"sig-name descname\">create_model_instance</span><span class=\"sig-paren\">(</span><em class=\"sig-param\">data</em><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.contrib.sessions.backends.db.SessionStore.create_model_instance\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>返回会话模型对象的新实例，该实例表示当前会话状态。</p>\n<p>重写此方法提供了在将会话模型数据保存到数据库之前修改它的能力。</p>\n</dd></dl>\n\n</dd></dl>\n\n<dl class=\"py class\">\n<dt class=\"sig sig-object py\" id=\"django.contrib.sessions.backends.cached_db.SessionStore\">\n<em class=\"property\"><span class=\"k\">class</span> </em><span class=\"sig-prename descclassname\">backends.cached_db.</span><span class=\"sig-name descname\">SessionStore</span><a class=\"heading-anchor\" href=\"#django.contrib.sessions.backends.cached_db.SessionStore\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>实现缓存数据库支持的会话存储。</p>\n<dl class=\"py attribute\">\n<dt class=\"sig sig-object py\" id=\"django.contrib.sessions.backends.cached_db.SessionStore.cache_key_prefix\">\n<span class=\"sig-name descname\">cache_key_prefix</span><a class=\"heading-anchor\" href=\"#django.contrib.sessions.backends.cached_db.SessionStore.cache_key_prefix\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>添加到会话键中以生成缓存键字符串的前缀。</p>\n</dd></dl>\n\n</dd></dl>\n\n<section id=\"example\">\n<h3>例如<a class=\"heading-anchor\" href=\"#example\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>下面的示例显示了一个自定义数据库支持的会话引擎，它包括一个用于存储帐户id的附加数据库列（从而提供了一个选项，用于查询数据库中帐户的所有活动会话）：</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"kn\">from</span> <span class=\"nn\">django.contrib.sessions.backends.db</span> <span class=\"kn\">import</span> SessionStore <span class=\"k\">as</span> DBStore\n<span class=\"kn\">from</span> <span class=\"nn\">django.contrib.sessions.base_session</span> <span class=\"kn\">import</span> AbstractBaseSession\n<span class=\"kn\">from</span> <span class=\"nn\">django.db</span> <span class=\"kn\">import</span> models\n\n<span class=\"k\">class</span> <span class=\"nc\">CustomSession</span><span class=\"p\">(</span>AbstractBaseSession<span class=\"p\">):</span>\n    account_id <span class=\"o\">=</span> models<span class=\"o\">.</span>IntegerField<span class=\"p\">(</span>null<span class=\"o\">=</span><span class=\"kc\">True</span><span class=\"p\">,</span> db_index<span class=\"o\">=</span><span class=\"kc\">True</span><span class=\"p\">)</span>\n\n    <span class=\"nd\">@classmethod</span>\n    <span class=\"k\">def</span> <span class=\"nf\">get_session_store_class</span><span class=\"p\">(</span><span class=\"bp\">cls</span><span class=\"p\">):</span>\n        <span class=\"k\">return</span> SessionStore\n\n<span class=\"k\">class</span> <span class=\"nc\">SessionStore</span><span class=\"p\">(</span>DBStore<span class=\"p\">):</span>\n    <span class=\"nd\">@classmethod</span>\n    <span class=\"k\">def</span> <span class=\"nf\">get_model_class</span><span class=\"p\">(</span><span class=\"bp\">cls</span><span class=\"p\">):</span>\n        <span class=\"k\">return</span> CustomSession\n\n    <span class=\"k\">def</span> <span class=\"nf\">create_model_instance</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> data<span class=\"p\">):</span>\n        obj <span class=\"o\">=</span> <span class=\"nb\">super</span><span class=\"p\">()</span><span class=\"o\">.</span>create_model_instance<span class=\"p\">(</span>data<span class=\"p\">)</span>\n        <span class=\"k\">try</span><span class=\"p\">:</span>\n            account_id <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span>data<span class=\"o\">.</span>get<span class=\"p\">(</span><span class=\"s1\">&#39;_auth_user_id&#39;</span><span class=\"p\">))</span>\n        <span class=\"k\">except</span> <span class=\"p\">(</span><span class=\"ne\">ValueError</span><span class=\"p\">,</span> <span class=\"ne\">TypeError</span><span class=\"p\">):</span>\n            account_id <span class=\"o\">=</span> <span class=\"kc\">None</span>\n        obj<span class=\"o\">.</span>account_id <span class=\"o\">=</span> account_id\n        <span class=\"k\">return</span> obj\n</code></pre></div>\n<p>如果要从Django的内置 <code class=\"docutils literal notranslate\">cached_db</code> 会话存储迁移到基于``cached_db`` 的自定义存储，则应重写缓存键前缀，以防止名称空间冲突：</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"k\">class</span> <span class=\"nc\">SessionStore</span><span class=\"p\">(</span>CachedDBStore<span class=\"p\">):</span>\n    cache_key_prefix <span class=\"o\">=</span> <span class=\"s1\">&#39;mysessions.custom_cached_db_backend&#39;</span>\n\n    <span class=\"c1\"># ...</span>\n</code></pre></div>\n</section>\n</section>\n<section id=\"session-ids-in-urls\">\n<h2>URL中的会话ID<a class=\"heading-anchor\" href=\"#session-ids-in-urls\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>Django会话框架完全是基于cookie的。 正如PHP所做的那样，它不会回退到将会话ID放置在URL中作为最后的手段。 这是一个有意设计的决定。 这种行为不仅使URL变得很难看，而且使您的站点容易受到会话ID的盗用。</p>\n</section>","rootId":"module-django.contrib.sessions","toc":[{"title":"打开会话","anchor":"enabling-sessions","children":[]},{"title":"配置会话(session)引擎","anchor":"configuring-the-session-engine","children":[{"title":"使用数据库支持的会话","anchor":"using-database-backed-sessions","children":[]},{"title":"使用缓存会话","anchor":"using-cached-sessions","children":[]},{"title":"使用基于文件的会话","anchor":"using-file-based-sessions","children":[]},{"title":"使用基于cookie的会话","anchor":"using-cookie-based-sessions","children":[]}]},{"title":"在视图中使用会话","anchor":"using-sessions-in-views","children":[{"title":"会话序列化","anchor":"session-serialization","children":[{"title":"绑定序列化","anchor":"bundled-serializers","children":[]},{"title":"编写自定义的序列化器","anchor":"write-your-own-serializer","children":[]}]},{"title":"会话对象指南","anchor":"session-object-guidelines","children":[]},{"title":"示例","anchor":"examples","children":[]}]},{"title":"测试 cookies 设置","anchor":"setting-test-cookies","children":[]},{"title":"在视图外使用会话","anchor":"using-sessions-out-of-views","children":[]},{"title":"当保存会话时","anchor":"when-sessions-are-saved","children":[]},{"title":"Browser-length 会话 vs 持久会话","anchor":"browser-length-sessions-vs-persistent-sessions","children":[]},{"title":"清除会话存储","anchor":"clearing-the-session-store","children":[]},{"title":"配置","anchor":"settings","children":[]},{"title":"会话安全","anchor":"session-security","children":[]},{"title":"技术细节","anchor":"technical-details","children":[{"title":"SessionStore 对象","anchor":"the-sessionstore-object","children":[]}]},{"title":"扩展数据库支持的会话引擎","anchor":"extending-database-backed-session-engines","children":[{"title":"例如","anchor":"example","children":[]}]},{"title":"URL中的会话ID","anchor":"session-ids-in-urls","children":[]}],"breadcrumbs":[{"docname":"topics/index","title":"使用 Django","url":"/zh-hans/4.1/topics/"},{"docname":"topics/http/index","title":"处理 HTTP 请求","url":"/zh-hans/4.1/topics/http/"}],"prev":{"docname":"topics/http/middleware","title":"中间件","url":"/zh-hans/4.1/topics/http/middleware/"},"next":{"docname":"topics/forms/index","title":"使用表单","url":"/zh-hans/4.1/topics/forms/"},"formats":{"html":"/zh-hans/4.1/topics/http/sessions/","markdown":"/zh-hans/4.1/topics/http/sessions.md","json":"/zh-hans/4.1/topics/http/sessions.json"},"source":"https://github.com/django/django/blob/stable/4.1.x/docs/topics/http/sessions.txt","official":"https://docs.djangoproject.com/zh-hans/4.1/topics/http/sessions/","inVersions":["6.1","6.0","5.2","5.1","5.0","4.2","4.1","4.0","3.2","3.1","3.0","2.2","2.1","2.0"],"inLocales":["en","zh-hans","fr","ja","id","it","pt-br","ko","es","el","pl"]}