aboutsummaryrefslogtreecommitdiff
path: root/files/zh-tw/learn/server-side/django/sessions/index.html
blob: 86b534adaf2c0fac7099753a457d4894e535e4c5 (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
---
title: 'Django Tutorial Part 7: Sessions framework'
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">本教程擴展了我們的<a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Django/Tutorial_local_library_website">LocalLibrary</a> 網站,為主頁添加了一個基於會話的訪問計數器。這是一個相對簡單的例子,但它確實顯示了,如何使用會話框架,為匿名用戶提供持久的行為。</p>

<table class="learn-box standard-table">
 <tbody>
  <tr>
   <th scope="row">Prerequisites:</th>
   <td>Complete all previous tutorial topics, including <a href="/en-US/docs/Learn/Server-side/Django/Generic_views">Django Tutorial Part 6: Generic list and detail views</a></td>
  </tr>
  <tr>
   <th scope="row">Objective:</th>
   <td>To understand how sessions are used.</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>會話框架允許您實現這種行為,從而允許您基於每個站點訪問者存儲和檢索任意數據。</p>

<h2 id="What_are_sessions">What are sessions?</h2>

<p>Web瀏覽器和服務器之間的所有通信都是通過HTTP協議進行的,該協議是無狀態的。該協議是無狀態的事實意味著客戶端和服務器之間的消息是完全相互獨立的-沒有基於先前消息的“序列”或行為的概念。因此,如果您想擁有一個跟踪與客戶之間正在進行的關係的站點,則需要自己實施。</p>

<p>會話是Django(以及大多數Internet)使用的機制,用於跟踪站點與特定瀏覽器之間的“狀態”。會話允許您在每個瀏覽器中存儲任意數據,並且只要瀏覽器連接,該數據就可用於站點。然後,與會話相關聯的單個數據項被一個``鍵''引用,該鍵既用於存儲又用於檢索數據。</p>

<p>Django使用包含特殊會話ID的cookie來標識每個瀏覽器及其與站點的關聯會話。默認情況下,實際會話數據默認存儲在站點數據庫中(這比將數據存儲在cookie中更安全,因為cookie在cookie中更容易受到惡意用戶的攻擊)。您可以將Django配置為將會話數據存儲在其他位置(緩存,文件或是“安全” Cookie),但是默認位置是一個很好且相對安全的選擇。</p>

<h2 id="Enabling_sessions">Enabling sessions</h2>

<p>當我們<a href="https://developer.mozilla.org/zh-TW/docs/Learn/Server-side/Django/skeleton_website">創建框架網站</a>時(在教程2中),將自動啟用會話。</p>

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

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

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

<h2 id="Using_sessions">Using sessions</h2>

<p>您可以從<code>request</code> 參數(作為視圖的第一個參數傳入的<code>HttpRequest</code> )中訪問視圖中的<code>session</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 notranslate"># 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/">How to use sessions</a> 找到完整的API(Django文檔)。</p>

<h2 id="Saving_session_data">Saving session data</h2>

<p>默認情況下,當會話已被修改(分配)或刪除時,Django僅保存到會話數據庫並將會話cookie發送給客戶端。 如果您要使用上一節中所示的會話密鑰更新某些數據,則無需擔心! 例如:</p>

<pre class="brush: python notranslate"># 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 notranslate"># 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>:您可以更改行為,以便站點可以通過在您的項目設置(<strong>locallibrary/locallibrary/settings.py</strong>)中添加<code>SESSION_SAVE_EVERY_REQUEST = True</code> 來更新每個請求的數據庫/發送cookie。</p>
</div>

<h2 id="Simple_example_—_getting_visit_counts">Simple example — getting visit counts</h2>

<p>作為一個簡單的真實示例,我們將更新我們的庫以告知當前用戶他們訪問LocalLibrary主頁的次數。</p>

<p>打開/ <strong>/locallibrary/catalog/views.py</strong>,然後進行以下粗體顯示的更改。</p>

<pre class="brush: python notranslate">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>

<strong>    context = {
        'num_books': num_books,
        'num_instances': num_instances,
        'num_instances_available': num_instances_available,
        'num_authors': num_authors,
        'num_visits': num_visits,
    }</strong>

    # Render the HTML template index.html with the data in the context variable.
    return render(request, 'index.html', context=context)</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/">How to use sessions</a>)或設計我們的UI,以便無論是否支持cookie都無關緊要。</p>
</div>

<p>將以下區塊底部看到的行添加到``動態內容''部分底部的主HTML模板(<strong>/locallibrary/catalog/templates/index.html</strong>)中以顯示上下文變量:</p>

<pre class="brush: html notranslate">&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>

<h2 id="總結">總結</h2>

<p>現在,您知道使用會話來改善與匿名用戶的交互是多麼容易。</p>

<p>在接下來的文章中,我們將說明身份驗證和授權(權限)框架,並向您展示如何支持用戶帳戶。</p>

<h2 id="See_also">See also</h2>

<ul>
 <li><a href="https://docs.djangoproject.com/en/2.0/topics/http/sessions/">How to use sessions</a> (Django docs)</li>
</ul>

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

<h2 id="In_this_module">In this module</h2>

<ul>
 <li><a href="/en-US/docs/Learn/Server-side/Django/Introduction">Django introduction</a></li>
 <li><a href="/en-US/docs/Learn/Server-side/Django/development_environment">Setting up a Django development environment</a></li>
 <li><a href="/en-US/docs/Learn/Server-side/Django/Tutorial_local_library_website">Django Tutorial: The Local Library website</a></li>
 <li><a href="/en-US/docs/Learn/Server-side/Django/skeleton_website">Django Tutorial Part 2: Creating a skeleton website</a></li>
 <li><a href="/en-US/docs/Learn/Server-side/Django/Models">Django Tutorial Part 3: Using models</a></li>
 <li><a href="/en-US/docs/Learn/Server-side/Django/Admin_site">Django Tutorial Part 4: Django admin site</a></li>
 <li><a href="/en-US/docs/Learn/Server-side/Django/Home_page">Django Tutorial Part 5: Creating our home page</a></li>
 <li><a href="/en-US/docs/Learn/Server-side/Django/Generic_views">Django Tutorial Part 6: Generic list and detail views</a></li>
 <li><a href="/en-US/docs/Learn/Server-side/Django/Sessions">Django Tutorial Part 7: Sessions framework</a></li>
 <li><a href="/en-US/docs/Learn/Server-side/Django/Authentication">Django Tutorial Part 8: User authentication and permissions</a></li>
 <li><a href="/en-US/docs/Learn/Server-side/Django/Forms">Django Tutorial Part 9: Working with forms</a></li>
 <li><a href="/en-US/docs/Learn/Server-side/Django/Testing">Django Tutorial Part 10: Testing a Django web application</a></li>
 <li><a href="/en-US/docs/Learn/Server-side/Django/Deployment">Django Tutorial Part 11: Deploying Django to production</a></li>
 <li><a href="/en-US/docs/Learn/Server-side/Django/web_application_security">Django web application security</a></li>
 <li><a href="/en-US/docs/Learn/Server-side/Django/django_assessment_blog">DIY Django mini blog</a></li>
</ul>