aboutsummaryrefslogtreecommitdiff
path: root/files/zh-cn/learn/server-side/django/sessions/index.html
blob: d6b95b01577dfa896fd23ffd3d8452610c1e5037 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
---
title: 'Django 教程 7: 会话框架'
slug: learn/Server-side/Django/Sessions
translation_of: Learn/Server-side/Django/Sessions
---
<div>{{LearnSidebar}}</div>

<div>{{PreviousMenuNext("Learn/Server-side/Django/Generic_views", "Learn/Server-side/Django/authentication_and_sessions", "Learn/Server-side/Django")}}</div>

<p class="summary" style='font-style: normal; margin: 0px 0px 20px; padding: 20px 0px; border-width: 3px 0px; border-style: solid; border-color: rgb(131, 208, 242); max-width: 42rem; font-size: 1.25rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>本教程扩展了我们的</font></font><a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Django/Tutorial_local_library_website" style='font-style: normal; color: rgb(63, 135, 166); margin: 0px; padding: 0px; border: 0px; text-decoration: none; font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: 20px; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255);'><font><font>LocalLibrary</font></font></a><font><font>网站,为主页添加了一个基于会话的访问计数器。</font><font>这是一个相对简单的例子,但它确实显示了,如何使用会话框架为匿名用户提供持久的行为。</font></font></p>

<table class="learn-box standard-table">
 <tbody>
  <tr>
   <th scope="row">先决条件:</th>
   <td>完成之前的所有教程主题,包括<a href="/zh-CN/docs/Learn/Server-side/Django/Generic_views">Django教程6:通用列表和详细信息视图</a></td>
  </tr>
  <tr>
   <th scope="row">目标:</th>
   <td>了解会话的使用方式。</td>
  </tr>
 </tbody>
</table>

<h2 id="概览">概览</h2>

<p>我们在之前的教程中创建的<a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Django/Tutorial_local_library_website">LocalLibrary</a>网站,允许用户浏览目录中的书本和作者。虽然内容是从数据库动态生成的,但每个用户在使用站点时,基本上都可以访问相同的页面,和相同类型的信息。</p>

<p>在一个 “真实” 的图书馆中,您可能希望根据用户之前对站点的使用,首选项等,为个人用户提供自定义体验。例如,您可以在用户下次访问时,隐藏上次已经确认的警告消息。网站,或存储和尊重他们的偏好(例如,他们希望在每个页面上显示的搜索结果的数量)。</p>

<p><br>
 会话框架允许您实现此类行为,允许您基于每个站点访问者,以储存和检索任意数据。</p>

<h2 id="会话是什么?">会话是什么?</h2>

<p>Web浏览器和服务器之间的所有通信,都是通过HTTP协议进行的,该协议是无状态的。协议无状态的事实,意味着客户端和服务器之间的消息,完全相互独立 - 没有基于先前消息的“序列”或行为的概念。因此,如果您想拥有一个追踪与客户的持续关系的网站,您需要自己实现。</p>

<p>会话是Django(以及大多数Internet)用于跟踪站点和特定浏览器之间“状态”的机制。会话允许您为每个浏览器存储任意数据,并在浏览器连接时,将该数据提供给站点。然后,通过“密钥”引用与会话相关联的各个数据项,“密钥”用于存储和检索数据。</p>

<p>Django使用包含特殊会话ID的cookie,来识别每个浏览器,及其与该站点的关联会话。默认情况下,实际会话数据存储在站点数据库中(这比将数据存储在cookie中更安全,因为它们更容易受到恶意用户的攻击)。您可以将Django配置为,将会话数据存储在其他位置(缓存,文件,“安全”cookie),但默认位置是一个良好且相对安全的选项。</p>

<h2 id="启用会话">启用会话</h2>

<p>我们<a href="/zh-CN/docs/Learn/Server-side/Django/skeleton_website">创建骨架网站</a>时,会自动启用会话(在教程2中)。</p>

<p>配置在项目文件(<strong>locallibrary / locallibrary / settings.py</strong>)的<code>INSTALLED_APPS</code><code>MIDDLEWARE</code> 部分中设置,如下所示:</p>

<pre class="brush: python">INSTALLED_APPS = [
    ...
<strong>    'django.contrib.sessions',</strong>
    ....

MIDDLEWARE = [
    ...
<strong>    'django.contrib.sessions.middleware.SessionMiddleware',</strong>
    ....</pre>

<h2 id="使用会话">使用会话</h2>

<p>您可以从<code>request</code>请求参数访问视图中的<code>session</code>会话属性(作为视图的第一个参数传入的<code>HttpRequest</code>)。此会话属性,表示与当前用户的特定连接(或者更确切地说,是与当前浏览器的连接,由此站点的浏览器cookie中的会话ID标识)。</p>

<p>会话<code>session</code>属性是一个类似字典的对象,您可以在视图中多次读取和写入,并根据需要进行修改。您可以执行所有常规的字典操作,包括清除所有数据,测试是否存在密钥,循环数据等。大多数情况下,您只需使用标准 “字典” API,来获取和设置值。</p>

<p>下面的代码片段,显示了如何使用与当前会话(浏览器)关联的密钥“<code>my_car</code>”来获取,设置和删除某些数据。</p>

<div class="note">
<p><strong>注意</strong>: 关于Django的一个好处是,你不需要考虑在你的视图中,将会话与当前请求联系起来的机制。如果我们在视图中,使用下面的片段,我们就知道有关<code>my_car</code>的信息,仅与发送当前请求的浏览器相关联。</p>
</div>

<pre class="brush: python"># Get a session value by its key (e.g. 'my_car'), raising a KeyError if the key is not present
my_car = request.session['my_car']

# Get a session value, setting a default if it is not present ('mini')
my_car = request.session.get('my_car', 'mini')

# Set a session value
request.session['my_car'] = 'mini'

# Delete a session value
del request.session['my_car']
</pre>

<p>API还提供了许多其他方法,主要用于管理关联的会话cookie。例如,有一些方法,可以测试客户端浏览器,是否支持cookie,设置和检查cookie过期日期,以及从数据存储中清除过期的会话。您可以在<a href="https://docs.djangoproject.com/en/2.0/topics/http/sessions/">如何使用会话</a>(Django文档)中找到完整的API。</p>

<h2 id="保存会话数据">保存会话数据</h2>

<p>默认情况下,Django仅保存到会话数据库,并在会话被修改(分配)或删除时,将会话cookie发送到客户端。如果您使用会话密钥更新某些数据,如上一节所示,那么您无需担心这一点!例如:</p>

<pre class="brush: python"># This is detected as an update to the session, so session data is saved.
request.session['my_car'] = 'mini'</pre>

<p>如果您正在更新会话数据中的某些信息,那么Django将无法识别您已对会话进行了更改并保存了数据(例如,如果您要更改“<code>my_car</code>”数据中的“轮子”<code>wheels</code>数据,如下所示)。在这种情况下,您需要将会话明确标记为已修改。</p>

<pre class="brush: python"># Session object not directly modified, only data within the session. Session changes not saved!
request.session['my_car']['wheels'] = 'alloy'

# Set session as modified to force data updates/cookie to be saved.
<code>request.session.modified = True</code>
</pre>

<div class="note">
<p><strong>注意</strong>: 您可以通过将<code>SESSION_SAVE_EVERY_REQUEST = True</code>添加到项目设置(<strong>locallibrary/locallibrary/settings.py</strong>),以更改站点行为,站点将在每个请求上更新数据库/发送cookie。</p>
</div>

<h2 id="简单的例子_-_获取访问次数">简单的例子 - 获取访问次数</h2>

<p>作为一个简单的现实世界的例子,我们将更新我们的图书馆,告诉当前用户,他们访问 LocalLibrary 主页的次数。</p>

<p>打开<strong>/locallibrary/catalog/views.py</strong>,并在下面以粗体显示更改。</p>

<pre class="brush: python">def index(request):
    ...

    num_authors=Author.objects.count()  # The 'all()' is implied by default.

<strong>    # Number of visits to this view, as counted in the session variable.
    num_visits=request.session.get('num_visits', 0)
    request.session['num_visits'] = num_visits+1</strong>

    # Render the HTML template index.html with the data in the context variable.
    return render(
        request,
        'index.html',
<strong>        context={'num_books':num_books,'num_instances':num_instances,'num_instances_available':num_instances_available,'num_authors':num_authors,
            'num_visits':num_visits}, # num_visits appended</strong>
    )</pre>

<p>这里,我们首先得到'<code>num_visits</code>'会话密钥的值,如果之前没有设置,则将值设置为0。每次收到请求时,我们都会递增该值,并将其存回会话中(下次用户访问该页面时)。然后将<code>num_visits</code>变量,传递给上下文变量中的模板。</p>

<div class="note">
<p><strong>注意</strong>: 我们也可能会测试浏览器中是否支持cookie(请参阅<a href="https://docs.djangoproject.com/en/2.0/topics/http/sessions/">如何使用会话</a>作为示例),或设计我们的UI,以便无论cookie是否受支持都无关紧要。</p>
</div>

<p>将以下区块底部那一行,添加到主HTML模板(<strong>/locallibrary/catalog/templates/index.html</strong>)的 “动态内容” 部分底部,以显示上下文变量:</p>

<pre class="brush: html">&lt;h2&gt;Dynamic content&lt;/h2&gt;

&lt;p&gt;The library has the following record counts:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Books:&lt;/strong&gt; \{{ num_books }}&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Copies:&lt;/strong&gt; \{{ num_instances }}&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Copies available:&lt;/strong&gt; \{{ num_instances_available }}&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Authors:&lt;/strong&gt; \{{ num_authors }}&lt;/li&gt;
&lt;/ul&gt;

<strong>&lt;p&gt;You have visited this page \{{ num_visits }}{% if num_visits == 1 %} time{% else %} times{% endif %}.&lt;/p&gt;</strong>
</pre>

<p>保存更改,并重新启动测试服务器。每次刷新页面时,数字都应该更新。</p>

<ul>
</ul>

<h2 id="总结">总结</h2>

<p>你现在知道,使用sessions 改善与匿名使用者的互动,有多么容易了。</p>

<p>在我们的下一篇文章,我们将解释授权与许可框架,并演示如何支持使用者帐户。</p>

<h2 id="参见">参见</h2>

<ul>
 <li><a href="https://docs.djangoproject.com/en/2.0/topics/http/sessions/">如何使用会话</a> (Django 文档)</li>
</ul>

<p>{{PreviousMenuNext("Learn/Server-side/Django/Generic_views", "Learn/Server-side/Django/Authentication", "Learn/Server-side/Django")}}</p>

<p> </p>

<h2 id="本教程">本教程</h2>

<ul>
 <li><a href="/zh-CN/docs/Learn/Server-side/Django/Introduction">Django 介绍</a></li>
 <li><a href="/zh-CN/docs/Learn/Server-side/Django/development_environment">架设 Django 开发环境</a></li>
 <li><a href="/zh-CN/docs/Learn/Server-side/Django/Tutorial_local_library_website">Django 教程: The Local Library website</a></li>
 <li><a href="/zh-CN/docs/Learn/Server-side/Django/skeleton_website">Django 教程 2: Creating a skeleton website</a></li>
 <li><a href="/zh-CN/docs/Learn/Server-side/Django/Models">Django 教程 3: Using models</a></li>
 <li><a href="/zh-CN/docs/Learn/Server-side/Django/Admin_site">Django 教程 4: Django admin site</a></li>
 <li><a href="/zh-CN/docs/Learn/Server-side/Django/Home_page">Django 教程 5: Creating our home page</a></li>
 <li><a href="/zh-CN/docs/Learn/Server-side/Django/Generic_views">Django 教程 6: Generic list and detail views</a></li>
 <li><a href="/zh-CN/docs/Learn/Server-side/Django/Sessions">Django 教程 7: Sessions framework</a></li>
 <li><a href="/zh-CN/docs/Learn/Server-side/Django/Authentication">Django 教程 8: User authentication and permissions</a></li>
 <li><a href="/zh-CN/docs/Learn/Server-side/Django/Forms">Django 教程 9: Working with forms</a></li>
 <li><a href="/zh-CN/docs/Learn/Server-side/Django/Testing">Django 教程 10: Testing a Django web application</a></li>
 <li><a href="/zh-CN/docs/Learn/Server-side/Django/Deployment">Django 教程 11: Deploying Django to production</a></li>
 <li><a href="/zh-CN/docs/Learn/Server-side/Django/web_application_security">Django 网络应用安全</a></li>
 <li><a href="/zh-CN/docs/Learn/Server-side/Django/django_assessment_blog">DIY Django 微博</a></li>
</ul>

<p> </p>