セッションの使い方
| revision-up-to: | 7127 (0.97pre SVN) |
|---|
Django では匿名セッション (anonymous session) を完全にサポートしています。 セッションフレームワークを使うと、任意のデータをサイト訪問者単位 (per-site-visitor) で保存したり取得したりできます。セッションフレームワーク はサーバ側にデータを保存し、クッキーの送受信操作を抽象化します。クッキーに はセッション ID だけが保存され、データ自体は送受信されません。
セッションを有効にする
セッション機能は ミドルウェア として実装されています。
セッションを有効にするには、以下の作業が必要です:
セッション機能をオンオフするには MIDDLEWARE_CLASSES 設定を編集します。
MIDDLEWARE_CLASSES を編集して、 'django.contrib.sessions.middleware.SessionMiddleware' を入れます。 django-admiin.py startproject の作成するデフォルトの settings.py では SessionMiddleware が有効になっています。
INSTALLED_APPS 設定に 'django.contrib.sessions' を入れ、 manage.py syncdb を実行して、セッションデータを保存するためのデー タベーステーブルを作成します。
開発版の Django で新たに追加された機能です データベースによるセッ ションバックエンドを使っていない場合は、このステップは不要です。
セッション機能を必要としないのなら、 MIDDLEWARE_CLASSES から SessionMiddleware の行を削り、 INSTALLED_APPS からも 'django.contrib.sessions' を削って下さい。セッションを無効にすると、ほ んのわずかだけオーバヘッドを軽減できます。
セッションエンジンの設定
開発版の Django で新たに追加された機能です
デフォルトでは、 Django はセッションをデータベースに (django.contrib.sessions.models.Session モデルを使って) 保存します。こ の仕様は便利ではありますが、場合によっては、データベース以外の場所、ファイ ルシステムやキャッシュ上にセッションデータを保存する方が高速です。
ファイルベースのセッション
ファイルベースのセッションを使うには、 SESSION_ENGINE 設定を "django.contrib.sessions.backends.file" にします。
また、必要に応じて SESSION_FILE_PATH も設定してください (デフォルト値は /tmp です)。 Web サーバが SESSION_FILE_PATH の場所にファイルの読書 き権限を持っているか確かめてください。
キャッシュベースのセッション
Django のキャッシュシステムにセッションデータを保存するには、 SESSION_ENGINE に "django.contrib.sessions.backends.cache" を設定してください。キャッシュを設定済みか確かめてください。詳しくは キャッシュのドキュメント を参照してください。
Note
memcached をキャッシュバックエンドとして使っているなら、キャッシュベー スのセッションを使うべきです。このバックエンドはローカルのオンメモリ に、単純なキャッシュで十分な期間データを保存できるので最もお勧めです。 一方、ファイルやデータベースによるキャッシュバックエンドを使うよりも、 ファイルやデータベース自体から直接データを読み出す方がはるかに高速です。
ビュー中でセッションを扱う
SessionMiddleware を有効にすると、各々の HttpRequest オブジェクト (Django ビュー関数の最初の引数) は辞書ライクオブジェクトの属性 session を持つようになります。この属性は読み書き可能です。
session は以下のような標準辞書オブジェクトのメソッドを実装しています:
__getitem__(key) 例: fav_color = request.session['fav_color']
__setitem__(key, value) 例: request.session['fav_color'] = 'blue'
__delitem__(key) 例: del request.session['fav_color']
key がない場合には KeyError を送出します。
__contains__(key) 例: 'fav_color' in request.session
get(key, default=None) 例: fav_color = request.session.get('fav_color', 'red')
keys()
items()
setdefault() (開発版の Django で新たに追加された機能です)
また、以下の三つのメソッドを持ちます:
- set_test_cookie() テストクッキーを設定して、ユーザのブラウザがクッキーをサポートしてい るかどうかを調べられるようにします。クッキーの動作仕様上、次にブラウ ザがリクエストを送信してくるまでテストは行えません。詳しくは後述の 「テストクッキーを設定する」を参照してください。
- test_cookie_worked() ユーザのブラウザがテストクッキーを受け入れたかどうかに応じて True または False を返します。クッキーの動作仕様上、あらかじめ別のペー ジリクエストで set_test_cookie() を呼び出しておかねばなりません。 後述の「テストクッキーを設定する」を参照してください。
- delete_test_cookie() テストクッキーを削除します。後始末に使って下さい。
request.session はビューのどこで変更しても、何度変更してもかまいません。
セッションオブジェクト使用上のガイドライン
- request.session のキーには通常の Python 文字列を使って下さい。と はいえ、これは厳格な掟 (hard-and-fast rule) ではなく単なる規約です。
- アンダースコアで始まるセッション辞書のキーは Django の内部使用のため に予約されています。
- request.session を新たなオブジェクトでオーバライドしたり、属性を いじってはなりません。Python 辞書型のように扱って下さい。
使用例
以下の簡単なビューの例では、ユーザがコメントをポストした後に has_commented という変数を True に設定しています。これにより、一人 のユーザに一つのコメントを何度もポストさせないようにします:
def post_comment(request, new_comment):
if request.session.get('has_commented', False):
return HttpResponse("You've already commented.")
c = comments.Comment(comment=new_comment)
c.save()
request.session['has_commented'] = True
return HttpResponse('Thanks for your comment!')
以下のビューでは、「メンバ」をサイトにログインさせます:
def login(request):
m = Member.objects.get(username__exact=request.POST['username'])
if m.password == request.POST['password']:
request.session['member_id'] = m.id
return HttpResponse("You're logged in.")
else:
return HttpResponse("Your username and password didn't match.")
そして下の例では、上で login() したメンバをログアウトさせます:
def logout(request):
try:
del request.session['member_id']
except KeyError:
pass
return HttpResponse("You're logged out.")
テストクッキーを設定する
利便性のために、 Django ではユーザのブラウザがクッキーを受け入れるかどうか を調べるための簡単な方法を提供しています。ビュー内で request.session.set_test_cookie() を呼び出しておき、それ以後のビュー、 すなわち別のビュー呼び出しで request.session.test_cookie_worked() を呼び出すようにしてください。
set_test_cookie() と test_cookie_worked() が別々のビュー呼び出しに 分離されるのは不恰好ですが、これはクッキーの動作上仕方のないことです。ある ブラウザに対して一度クッキーを設定しても、そのブラウザが次にリクエストを送 信するまではクッキーを受け入れたかどうかを確かめる術はないのです。
テストが終わったら、 delete_test_cookie() を呼び出して後始末をしておく のがよいでしょう。
クッキーの動作テストが終わった時点で、この関数を呼び出して下さい。
典型的な使用例を以下に示します:
def login(request):
if request.method == 'POST':
if request.session.test_cookie_worked():
request.session.delete_test_cookie()
return HttpResponse("You're logged in.")
else:
return HttpResponse("Please enable cookies and try again.")
request.session.set_test_cookie()
return render_to_response('foo/login_form.html')
ビューの外でセッションを使う
開発版の Django で新たに追加された機能です
API を使うと、ビューの外からセッションデータを操作できます:
>>> from django.contrib.sessions.backends.db import SessionStore >>> s = SessionStore(session_key='2b1189a188b44ad18c35e113ac6ceead') >>> s['last_login'] = datetime.datetime(2005, 8, 20, 13, 35, 10) >>> s['last_login'] datetime.datetime(2005, 8, 20, 13, 35, 0) >>> s.save()
django.contrib.sessions.backends.db バックエンドを使っている場合、各セッ ションは Django のモデルインスタンスで表現されています。 Session モデル は django/contrib/session/models.py で定義されています。 Session は 通常のモデルなので、通常の Django データベース API でアクセスできます:
>>> from django.contrib.sessions.models import Session >>> s = Session.objects.get(pk='2b1189a188b44ad18c35e113ac6ceead') >>> s.expire_date datetime.datetime(2005, 8, 20, 13, 35, 12)
セッション情報の辞書を取得するには get_decoded() を呼び出す必要があるの で注意して下さい。というのも、セッション情報はエンコードされた形式で保存さ れているからです。
>>> s.session_data
'KGRwMQpTJ19hdXRoX3VzZXJfaWQnCnAyCkkxCnMuMTExY2ZjODI2Yj...'
>>> s.get_decoded()
{'user_id': 42}
セッションはいつ保存されるのか
デフォルトでは、 Django はセッション情報が変更された場合、すなわちセッショ ン情報の入った辞書に値を代入したり、値を削除した場合にのみ、セッションデー タベースを保存します:
# セッションデータは変更されたものとみなされます
request.session['foo'] = 'bar'
# セッションデータは変更されたものとみなされます
del request.session['foo']
# セッションデータは変更されたものとみなされます
request.session['foo'] = {}
# 落とし穴: request.session ではなく request.session['foo'] の変更なの
# で、セッションデータは変更されたものとみなされません。
request.session['foo']['bar'] = 'baz'
上の例の最後のケースでは、セッションオブジェクトに内容が変更されたことを明 示的に教えねばなりません。変更の通知は modified 属性で行います:
request.session.modified = True
この振舞いを変更したければ、 SESSION_SAVE_EVERY_REQUEST 設定を True に設定してください。 SESSION_SAVE_EVERY_REQUEST を True にすると、 Django はリクエスト一つ一つに対してセッションを保存します。
セッションクッキーはセッションが作成されたり変更されたりした場合にのみ送信 されることに注意してください。 SESSION_SAVE_EVERY_REQUEST を True にすると、リクエストごとに必ずセッションクッキーを送信するようになります。
同様に、セッションクッキーの expires 部分もセッションクッキーの送信ごと に更新されます。
ブラウザアクセス単位のセッションと永続的セッション
SESSION_EXPIRE_AT_BROWSER_CLOSE 設定を使うと、セッションフレームワーク に、ブラウザアクセス単位のセッションと永続的セッションのどちらを使わせるか を指定できます。
デフォルトでは、 SESSION_EXPIRE_AT_BROWSER_CLOSE は False に設定さ れています。これはセッションクッキーが SESSION_COOKIE_AGE の間だけブラ ウザに保存されることを示します。ユーザがブラウザを起動するたびにログインし なくてもすむようにしたければ、この設定を使ってください。
SESSION_EXPIRE_AT_BROWSER_CLOSE を True にすると、 Django はブラウ ザアクセス単位のクッキー、すなわちユーザがブラウザを閉じると有効期限が切れ るようなクッキーを使うようになります。ブラウザを起動するたびにユーザにログ イン操作を行わせたい場合、この設定を使ってください。
セッションテーブルの消去
セッションデータは django_session データベーステーブル上に蓄積されます が、 Django はセッションテーブルを自動的に清掃 しません。 つまり、期限切 れの (expired) セッションデータを正しい判断基準の下に削除するのは、アプリケー ション開発者であるあなた自身の仕事なのです。
この問題を理解するには、ユーザがセッションを使ったときに何が起きているかを 考える必要があります。ユーザがログインすると、 Django は django_session データベーステーブルにレコードを 1 行追加します。セッションデータが変更され る度に、このレコード行は更新されてゆきます。ユーザが手動でログアウトすれば、 レコード行は削除されますが、ユーザがログアウト操作を しなかった場合 には、 レコード行は削除されません。
Django には、クリーンアップ用のサンプルスクリプト、 django/bin/daily_cleanup.py が付属しています。このスクリプトは セッションテーブルの全てのエントリの中から、 expire_date の値が過去を指 しているものを除去します。もちろん、お使いのアプリケーションが要求する仕様 が異なる場合には、別のスクリプトを用意する必要があるでしょう。
設定
Django 設定ファイル には、セッションの振舞いを操作するための設定がいくつ かあります:
SESSION_ENGINE
開発版の Django で新たに追加された機能です
デフォルト値: django.contrib.sessions.backends.db
Django がセッションデータを保存する方法を指定します。利用できる値は以下の通 りです:
- 'django.contrib.sessions.backends.db'
- 'django.contrib.sessions.backends.file'
- 'django.contrib.sessions.backends.cache'
詳しくは セッションエンジンの設定 を参照してください。
SESSION_FILE_PATH
開発版の Django で新たに追加された機能です
デフォルト値: /tmp/
ファイルベースのセッションストレージを使っている場合、この値でセッションデー タの保存場所を指定します。
SESSION_COOKIE_DOMAIN
デフォルト値: None
セッションクッキーを使うドメインです。クロスドメインのクッキーを使う場合に は ".lawrence.com" といった値に、通常のドメイン内クッキーの場合には None を指定します。
SESSION_COOKIE_SECURE
デフォルト値: False
セッションクッキーにセキュアなクッキーを使うかどうかを決めます。この値を True に設定すると、クッキーは "セキュア" にマークされます。クッキーがセ キュアにマークされると、ブラウザによっては HTTPS 接続でのみクッキーを転送す るようになります。
SESSION_SAVE_EVERY_REQUEST
デフォルト値: False
リクエストごとにセッションデータを保存するかどうかを決めます。この値が False (デフォルト) の場合、セッションデータの保存は内容が変更された場合、 すなわちセッションデータ辞書に値を設定したり、値を削除したりした場合だけに なります。
技術的な詳細
- セッション辞書には pickle 化可能な全てのオブジェクトを使えます。詳し くは pickle モジュールのドキュメント を参照してください。
- セッション情報は django_session という名前のデータベーステーブルに 保存されます。
- Django は必要なときにしかクッキーを送信しません。従って、セッション情 報を設定しない限り、セッションクッキーの送信を行いません。
URL と Session ID
Django のセッションフレームワークは完全なクッキーベースであり、クッキー以外 の情報を扱いません。従って、 PHP のように URL にセッション ID を入れる方法 を最後の手段に残したりはしていません。これは設計上の意図的な決定です。とい うのも、URL にセッション ID を含めると、みっともない URL になるだけでなく、 "Referer" ヘッダを使ってセッション ID を盗まれるという脆弱性を招くからです。