|
1 =================== |
|
2 How to use sessions |
|
3 =================== |
|
4 |
|
5 Django provides full support for anonymous sessions. The session framework lets |
|
6 you store and retrieve arbitrary data on a per-site-visitor basis. It stores |
|
7 data on the server side and abstracts the sending and receiving of cookies. |
|
8 Cookies contain a session ID -- not the data itself. |
|
9 |
|
10 Enabling sessions |
|
11 ================= |
|
12 |
|
13 Sessions are implemented via a piece of middleware_ and a Django model. |
|
14 |
|
15 To enable session functionality, do these two things: |
|
16 |
|
17 * Edit the ``MIDDLEWARE_CLASSES`` setting and make sure |
|
18 ``MIDDLEWARE_CLASSES`` contains ``'django.contrib.sessions.middleware.SessionMiddleware'``. |
|
19 The default ``settings.py`` created by ``django-admin.py startproject`` has |
|
20 ``SessionMiddleware`` activated. |
|
21 |
|
22 * Add ``'django.contrib.sessions'`` to your ``INSTALLED_APPS`` setting, and |
|
23 run ``manage.py syncdb`` to install the single database table that stores |
|
24 session data. |
|
25 |
|
26 If you don't want to use sessions, you might as well remove the |
|
27 ``SessionMiddleware`` line from ``MIDDLEWARE_CLASSES`` and ``'django.contrib.sessions'`` |
|
28 from your ``INSTALLED_APPS``. It'll save you a small bit of overhead. |
|
29 |
|
30 .. _middleware: ../middleware/ |
|
31 |
|
32 Using sessions in views |
|
33 ======================= |
|
34 |
|
35 When ``SessionMiddleware`` is activated, each ``HttpRequest`` object -- the |
|
36 first argument to any Django view function -- will have a ``session`` |
|
37 attribute, which is a dictionary-like object. You can read it and write to it. |
|
38 |
|
39 It implements the following standard dictionary methods: |
|
40 |
|
41 * ``__getitem__(key)`` |
|
42 Example: ``fav_color = request.session['fav_color']`` |
|
43 |
|
44 * ``__setitem__(key, value)`` |
|
45 Example: ``request.session['fav_color'] = 'blue'`` |
|
46 |
|
47 * ``__delitem__(key)`` |
|
48 Example: ``del request.session['fav_color']``. This raises ``KeyError`` |
|
49 if the given ``key`` isn't already in the session. |
|
50 |
|
51 * ``__contains__(key)`` |
|
52 Example: ``'fav_color' in request.session`` |
|
53 |
|
54 * ``get(key, default=None)`` |
|
55 Example: ``fav_color = request.session.get('fav_color', 'red')`` |
|
56 |
|
57 * ``keys()`` |
|
58 |
|
59 * ``items()`` |
|
60 |
|
61 It also has these three methods: |
|
62 |
|
63 * ``set_test_cookie()`` |
|
64 Sets a test cookie to determine whether the user's browser supports |
|
65 cookies. Due to the way cookies work, you won't be able to test this |
|
66 until the user's next page request. See "Setting test cookies" below for |
|
67 more information. |
|
68 |
|
69 * ``test_cookie_worked()`` |
|
70 Returns either ``True`` or ``False``, depending on whether the user's |
|
71 browser accepted the test cookie. Due to the way cookies work, you'll |
|
72 have to call ``set_test_cookie()`` on a previous, separate page request. |
|
73 See "Setting test cookies" below for more information. |
|
74 |
|
75 * ``delete_test_cookie()`` |
|
76 Deletes the test cookie. Use this to clean up after yourself. |
|
77 |
|
78 You can edit ``request.session`` at any point in your view. You can edit it |
|
79 multiple times. |
|
80 |
|
81 Session object guidelines |
|
82 ------------------------- |
|
83 |
|
84 * Use normal Python strings as dictionary keys on ``request.session``. This |
|
85 is more of a convention than a hard-and-fast rule. |
|
86 |
|
87 * Session dictionary keys that begin with an underscore are reserved for |
|
88 internal use by Django. |
|
89 |
|
90 * Don't override ``request.session`` with a new object, and don't access or |
|
91 set its attributes. Use it like a Python dictionary. |
|
92 |
|
93 Examples |
|
94 -------- |
|
95 |
|
96 This simplistic view sets a ``has_commented`` variable to ``True`` after a user |
|
97 posts a comment. It doesn't let a user post a comment more than once:: |
|
98 |
|
99 def post_comment(request, new_comment): |
|
100 if request.session.get('has_commented', False): |
|
101 return HttpResponse("You've already commented.") |
|
102 c = comments.Comment(comment=new_comment) |
|
103 c.save() |
|
104 request.session['has_commented'] = True |
|
105 return HttpResponse('Thanks for your comment!') |
|
106 |
|
107 This simplistic view logs in a "member" of the site:: |
|
108 |
|
109 def login(request): |
|
110 m = members.get_object(username__exact=request.POST['username']) |
|
111 if m.password == request.POST['password']: |
|
112 request.session['member_id'] = m.id |
|
113 return HttpResponse("You're logged in.") |
|
114 else: |
|
115 return HttpResponse("Your username and password didn't match.") |
|
116 |
|
117 ...And this one logs a member out, according to ``login()`` above:: |
|
118 |
|
119 def logout(request): |
|
120 try: |
|
121 del request.session['member_id'] |
|
122 except KeyError: |
|
123 pass |
|
124 return HttpResponse("You're logged out.") |
|
125 |
|
126 Setting test cookies |
|
127 ==================== |
|
128 |
|
129 As a convenience, Django provides an easy way to test whether the user's |
|
130 browser accepts cookies. Just call ``request.session.set_test_cookie()`` in a |
|
131 view, and call ``request.session.test_cookie_worked()`` in a subsequent view -- |
|
132 not in the same view call. |
|
133 |
|
134 This awkward split between ``set_test_cookie()`` and ``test_cookie_worked()`` |
|
135 is necessary due to the way cookies work. When you set a cookie, you can't |
|
136 actually tell whether a browser accepted it until the browser's next request. |
|
137 |
|
138 It's good practice to use ``delete_test_cookie()`` to clean up after yourself. |
|
139 Do this after you've verified that the test cookie worked. |
|
140 |
|
141 Here's a typical usage example:: |
|
142 |
|
143 def login(request): |
|
144 if request.method == 'POST': |
|
145 if request.session.test_cookie_worked(): |
|
146 request.session.delete_test_cookie() |
|
147 return HttpResponse("You're logged in.") |
|
148 else: |
|
149 return HttpResponse("Please enable cookies and try again.") |
|
150 request.session.set_test_cookie() |
|
151 return render_to_response('foo/login_form.html') |
|
152 |
|
153 Using sessions out of views |
|
154 =========================== |
|
155 |
|
156 Internally, each session is just a normal Django model. The ``Session`` model |
|
157 is defined in ``django/contrib/sessions/models.py``. Because it's a normal |
|
158 model, you can access sessions using the normal Django database API:: |
|
159 |
|
160 >>> from django.contrib.sessions.models import Session |
|
161 >>> s = Session.objects.get_object(pk='2b1189a188b44ad18c35e113ac6ceead') |
|
162 >>> s.expire_date |
|
163 datetime.datetime(2005, 8, 20, 13, 35, 12) |
|
164 |
|
165 Note that you'll need to call ``get_decoded()`` to get the session dictionary. |
|
166 This is necessary because the dictionary is stored in an encoded format:: |
|
167 |
|
168 >>> s.session_data |
|
169 'KGRwMQpTJ19hdXRoX3VzZXJfaWQnCnAyCkkxCnMuMTExY2ZjODI2Yj...' |
|
170 >>> s.get_decoded() |
|
171 {'user_id': 42} |
|
172 |
|
173 When sessions are saved |
|
174 ======================= |
|
175 |
|
176 By default, Django only saves to the session database when the session has been |
|
177 modified -- that is if any of its dictionary values have been assigned or |
|
178 deleted:: |
|
179 |
|
180 # Session is modified. |
|
181 request.session['foo'] = 'bar' |
|
182 |
|
183 # Session is modified. |
|
184 del request.session['foo'] |
|
185 |
|
186 # Session is modified. |
|
187 request.session['foo'] = {} |
|
188 |
|
189 # Gotcha: Session is NOT modified, because this alters |
|
190 # request.session['foo'] instead of request.session. |
|
191 request.session['foo']['bar'] = 'baz' |
|
192 |
|
193 To change this default behavior, set the ``SESSION_SAVE_EVERY_REQUEST`` setting |
|
194 to ``True``. If ``SESSION_SAVE_EVERY_REQUEST`` is ``True``, Django will save |
|
195 the session to the database on every single request. |
|
196 |
|
197 Note that the session cookie is only sent when a session has been created or |
|
198 modified. If ``SESSION_SAVE_EVERY_REQUEST`` is ``True``, the session cookie |
|
199 will be sent on every request. |
|
200 |
|
201 Similarly, the ``expires`` part of a session cookie is updated each time the |
|
202 session cookie is sent. |
|
203 |
|
204 Browser-length sessions vs. persistent sessions |
|
205 =============================================== |
|
206 |
|
207 You can control whether the session framework uses browser-length sessions vs. |
|
208 persistent sessions with the ``SESSION_EXPIRE_AT_BROWSER_CLOSE`` setting. |
|
209 |
|
210 By default, ``SESSION_EXPIRE_AT_BROWSER_CLOSE`` is set to ``False``, which |
|
211 means session cookies will be stored in users' browsers for as long as |
|
212 ``SESSION_COOKIE_AGE``. Use this if you don't want people to have to log in |
|
213 every time they open a browser. |
|
214 |
|
215 If ``SESSION_EXPIRE_AT_BROWSER_CLOSE`` is set to ``True``, Django will use |
|
216 browser-length cookies -- cookies that expire as soon as the user closes his or |
|
217 her browser. Use this if you want people to have to log in every time they open |
|
218 a browser. |
|
219 |
|
220 Clearing the session table |
|
221 ========================== |
|
222 |
|
223 Note that session data can accumulate in the ``django_session`` database table |
|
224 and Django does *not* provide automatic purging. Therefore, it's your job to |
|
225 purge expired sessions on a regular basis. |
|
226 |
|
227 To understand this problem, consider what happens when a user uses a session. |
|
228 When a user logs in, Django adds a row to the ``django_session`` database |
|
229 table. Django updates this row each time the session data changes. If the user |
|
230 logs out manually, Django deletes the row. But if the user does *not* log out, |
|
231 the row never gets deleted. |
|
232 |
|
233 Django provides a sample clean-up script in ``django/bin/daily_cleanup.py``. |
|
234 That script deletes any session in the session table whose ``expire_date`` is |
|
235 in the past -- but your application may have different requirements. |
|
236 |
|
237 Settings |
|
238 ======== |
|
239 |
|
240 A few `Django settings`_ give you control over session behavior: |
|
241 |
|
242 SESSION_COOKIE_AGE |
|
243 ------------------ |
|
244 |
|
245 Default: ``1209600`` (2 weeks, in seconds) |
|
246 |
|
247 The age of session cookies, in seconds. |
|
248 |
|
249 SESSION_COOKIE_DOMAIN |
|
250 --------------------- |
|
251 |
|
252 Default: ``None`` |
|
253 |
|
254 The domain to use for session cookies. Set this to a string such as |
|
255 ``".lawrence.com"`` for cross-domain cookies, or use ``None`` for a standard |
|
256 domain cookie. |
|
257 |
|
258 SESSION_COOKIE_NAME |
|
259 ------------------- |
|
260 |
|
261 Default: ``'sessionid'`` |
|
262 |
|
263 The name of the cookie to use for sessions. This can be whatever you want. |
|
264 |
|
265 SESSION_COOKIE_SECURE |
|
266 --------------------- |
|
267 |
|
268 Default: ``False`` |
|
269 |
|
270 Whether to use a secure cookie for the session cookie. If this is set to |
|
271 ``True``, the cookie will be marked as "secure," which means browsers may |
|
272 ensure that the cookie is only sent under an HTTPS connection. |
|
273 |
|
274 SESSION_EXPIRE_AT_BROWSER_CLOSE |
|
275 ------------------------------- |
|
276 |
|
277 Default: ``False`` |
|
278 |
|
279 Whether to expire the session when the user closes his or her browser. See |
|
280 "Browser-length sessions vs. persistent sessions" above. |
|
281 |
|
282 SESSION_SAVE_EVERY_REQUEST |
|
283 -------------------------- |
|
284 |
|
285 Default: ``False`` |
|
286 |
|
287 Whether to save the session data on every request. If this is ``False`` |
|
288 (default), then the session data will only be saved if it has been modified -- |
|
289 that is, if any of its dictionary values have been assigned or deleted. |
|
290 |
|
291 .. _Django settings: ../settings/ |
|
292 |
|
293 Technical details |
|
294 ================= |
|
295 |
|
296 * The session dictionary should accept any pickleable Python object. See |
|
297 `the pickle module`_ for more information. |
|
298 |
|
299 * Session data is stored in a database table named ``django_session`` . |
|
300 |
|
301 * Django only sends a cookie if it needs to. If you don't set any session |
|
302 data, it won't send a session cookie. |
|
303 |
|
304 .. _`the pickle module`: http://www.python.org/doc/current/lib/module-pickle.html |
|
305 |
|
306 Session IDs in URLs |
|
307 =================== |
|
308 |
|
309 The Django sessions framework is entirely, and solely, cookie-based. It does |
|
310 not fall back to putting session IDs in URLs as a last resort, as PHP does. |
|
311 This is an intentional design decision. Not only does that behavior make URLs |
|
312 ugly, it makes your site vulnerable to session-ID theft via the "Referer" |
|
313 header. |