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
|
---
title: 'Руководство часть 7: Сессии'
slug: Learn/Server-side/Django/Sessions
tags:
- django
- Django
- Для начинающих
- Изучение
- Питон
- Руководство
- Серверная сторона
- Статья
- применение сессий
- сессии
translation_of: Learn/Server-side/Django/Sessions
original_slug: Learn/Server-side/Django/Сессии
---
<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">Требования:</th>
<td>Завершить изучение всех предыдущих разделов, включая <a href="/en-US/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>Сессии позволяют вам реализовать такой род функциональности, который позволит вам хранить и получать произвольные данные, полученные на основе индивидуального поведения пользователя на сайте.</p>
<h2 id="Что_такое_сессии">Что такое сессии?</h2>
<p>Все взаимодействия между браузерами и серверами осуществляются при помощи протокола HTTP, который не сохраняет своё состояние (<em>stateless)</em>. Данный факт означает, что сообщения между клиентом и сервером являются полностью независимыми один от другого — то есть не существует какого-либо представления "последовательности", или поведения в зависимости от предыдущих сообщений. В результате, если вы хотите создать сайт который будет отслеживать взаимодействие с клиентом (браузером), вам нужно реализовать это самостоятельно.</p>
<p>Сессии являются механизмом, который использует Django (да и весь остальной "Интернет") для отслеживания "состояния" между сайтом и каким-либо браузером. Сессии позволяют вам хранить произвольные данные браузера и получать их в тот момент, когда между данным браузером и сайтом устанавливается соединение. Данные получаются и сохраняются в сессии при помощи соответствующего "ключа".</p>
<p>Django использует куки (cookie), которые содержат специальный <em>идентификатор сессии,</em> который выделяет среди остальных, каждый браузер и соответствующую сессию. Реальные <em>данные</em> сессии, по умолчанию, хранятся в базе данных сайта (это более безопасно, чем сохранять данные в куки, где они могут быть уязвимы для злоумышленников). Однако, у вас есть возможность настроить Django так, чтобы сохранять данные сессий в других местах (кэше, файлах, "безопасных" куки). Но все же хранение по умолчанию является хорошей и безопасной возможностью.</p>
<h2 id="Подключение_сессий">Подключение сессий</h2>
<p>Сессии стали доступны автоматически в тот момент, когда мы <a href="/en-US/docs/Learn/Server-side/Django/skeleton_website">создали скелет сайта</a> (во второй части руководства).</p>
<p>Необходимые конфигурации выполняются в разделах <code>INSTALLED_APPS</code> и <code>MIDDLEWARE</code> файла проекта (<strong>locallibrary/locallibrary/settings.py</strong>), как показано ниже:</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>session</code>, в соответствующем отображении, через параметр <code>request</code> (<code>HttpRequest</code> передаётся как первый аргумент в каждое отображение). Переменная сессии является связью с определённым пользователем (или, если быть более точным, связью с определённым <em>браузером</em>, который определяется при помощи идентификатора (id) сессии, получаемого из куки браузера).</p>
<p>Переменная (или поле) <code>session</code> является объектом-словарём, который служит для чтения и записи неограниченное число раз. С ним вы можете выполнять любые стандартные операции, включая очистку всех данных, проверку наличия ключа, циклы по данным и так далее. Большую часть времени вы будете тратить на обычные "словарные" операции - получения и установки значений.</p>
<p>Ниже представлены фрагменты кода, которые показывают вам как получать, задавать и удалять некоторые данные при помощи ключа "<code>my_car</code>", связанного с текущей сессией (браузером). </p>
<div class="note">
<p><strong>Примечание</strong>: Одной из самых грандиозных вещей в Django является то, что вам не надо думать о механизме, который связывает сессию с текущим запросом в отображении. Во фрагменте ниже, все что вам надо знать, это то, что <code>my_car</code> связана с тем браузером, который отправил текущий запрос.</p>
</div>
<pre class="brush: python"># Получение значения сессии при помощи ключа(то есть, 'my_car').
# Если такого ключа нет, то возникнет ошибка KeyError
my_car = request.session['my_car']
# Получение значения сессии. Если значения не существует,
# то вернётся значение по умолчанию ('mini')
my_car = request.session.get('my_car', 'mini')
# Передача значения в сессию
request.session['my_car'] = 'mini'
# Удаление значения из сессии
del request.session['my_car']
</pre>
<p>Данное API имеет другие методы, которые большей частью используются для управления куки, связанных с сессией. Например, существуют методы проверки того, что куки поддерживаются клиентским браузером, другие методы служат для установки и проверки предельных дат жизни куки, а также для очистки просроченных сессий из хранилища. Подробное описание API вы можете найти в разделе <a href="https://docs.djangoproject.com/en/1.10/topics/http/sessions/">Как использовать сессии</a> (Django docs).</p>
<h2 id="Хранение_данных_сессии">Хранение данных сессии</h2>
<p>По умолчанию Django сохраняет данные сессии в базу данных и отправляет соответствующие куки клиенту только тогда, когда сессия была <em>изменена</em>, или <em>удалена</em>. Если вы обновляете какие-либо данные при помощи ключа сессии, как показано в предыдущем фрагменте, тогда вам не надо беспокоиться о процессе сохранения! Например:</p>
<pre class="brush: python"># Данное присваивание распознается как обновление сессии
# и данные будут сохранены
request.session['my_car'] = 'mini'</pre>
<p>Если вы обновлять информацию <em>внутри</em> данных сессии, тогда Django не распознает эти изменения и не выполнит сохранение данных (например, если вы изменили "<code>wheels</code>" внутри переменной "<code>my_car</code>", как показано ниже). В таких случаях вам надо явно указывать, что сессия была изменена.</p>
<pre class="brush: python"># Объект сессии модифицируется неявно.
# Изменения НЕ БУДУТ сохранены!
request.session['my_car']['wheels'] = 'alloy'
# Явное указание, что данные изменены.
# Сессия будет сохранена, куки обновлены (если необходимо).
<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>).</p>
</div>
<h2 id="Простой_пример_—_получение_числа_визитов">Простой пример — получение числа визитов</h2>
<p>В качестве примера из реального мира мы обновим нашу библиотеку так, чтобы сообщать пользователю количество совершенных им визитов главной страницы сайта <em>LocalLibrary</em>. </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> передаётся в шаблон через переменную контекста <code>context</code>. </p>
<div class="note">
<p><strong>Примечание</strong>: Можно проверить наличие поддержки куки в браузере (для примера, смотрите <a href="https://docs.djangoproject.com/en/1.10/topics/http/sessions/">Как использовать сессии</a>), или разработать наш UI таким образом, чтобы это не имело значения.</p>
</div>
<p>Для показа значения переменной, из следующего фрагмента добавьте нижнюю строчку кода в ваш шаблон главной страницы сайта (<strong>/locallibrary/catalog/templates/index.html</strong>), в его нижний раздел "Dynamic content":</p>
<pre class="brush: html"><h2>Dynamic content</h2>
<p>The library has the following record counts:</p>
<ul>
<li><strong>Books:</strong> \{{ num_books }}</li>
<li><strong>Copies:</strong> \{{ num_instances }}</li>
<li><strong>Copies available:</strong> \{{ num_instances_available }}</li>
<li><strong>Authors:</strong> \{{ num_authors }}</li>
</ul>
<strong><p>You have visited this page \{{ num_visits }}{% if num_visits == 1 %} time{% else %} times{% endif %}.</p></strong>
</pre>
<p>Сохраните ваши изменения и перезапустите сервер. Данное значение должно изменяться всякий раз, когда вы обновляете страницу.</p>
<ul>
</ul>
<h2 id="Итоги">Итоги</h2>
<p>Вы узнали как применять сессии для улучшения взаимодействие с <em>анонимными</em> пользователями. </p>
<p>В наших следующих статьях мы рассмотрим фреймворк аутентификации и авторизации (разрешение доступа, permission), и покажем вам как поддерживать пользовательские аккаунты.</p>
<h2 id="Смотрите_также">Смотрите также</h2>
<ul>
<li><a href="https://docs.djangoproject.com/en/1.10/topics/http/sessions/">Как использовать сессии</a> (Django docs)</li>
</ul>
<p>{{PreviousMenuNext("Learn/Server-side/Django/Generic_views", "Learn/Server-side/Django/Authentication", "Learn/Server-side/Django")}}</p>
|