revision-up-to: | 8961 (1.0) |
---|
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 を実行して、セッションデータを保存するためのデー タベーステーブルを作成します。
データベースによるセッションバックエンドを使っていない場合は、このス テップは不要です。
セッション機能を必要としないのなら、 MIDDLEWARE_CLASSES から SessionMiddleware の行を削り、 INSTALLED_APPS からも 'django.contrib.sessions' を削って下さい。セッションを無効にすると、ほ んのわずかだけオーバヘッドを軽減できます。
デフォルトでは、 Django はセッションをデータベースに (django.contrib.sessions.models.Session モデルを使って) 保存します。こ の仕様は便利ではありますが、場合によっては、データベース以外の場所、ファイ ルシステムやキャッシュ上にセッションデータを保存する方が高速です。
ファイルベースのセッションを使うには、 SESSION_ENGINE 設定を "django.contrib.sessions.backends.file" にします。
また、必要に応じて SESSION_FILE_PATH も設定してください (デフォルト値は tempfile.gettempdir() の戻り値で、たいていは /tmp です)。 Web サー バが SESSION_FILE_PATH の場所にファイルの読書き権限を持っているか確かめ てください。
Django のキャッシュシステムにセッションデータを保存するには、 SESSION_ENGINE に "django.contrib.sessions.backends.cache" を設定してください。キャッシュを設定済みか確かめてください。詳しくは キャッシュのドキュメント を参照してください。
Note
Memcached をキャッシュバックエンドとして使っているなら、キャッシュベー スのセッションを使うべきです。ローカルメモリ型のキャッシュバックエンド は十分な時間データを保持できないので、よい選択肢とはいえません。また、 ファイルやデータベースによるキャッシュバックエンドを使っている場合、何 もかもをキャッシュに放り込むより、直接ファイルやデータベースからデータ を出力する方がはるかに高速です。
SessionMiddleware を有効にすると、各々の HttpRequest オブジェクト (Django ビュー関数の最初の引数) は辞書ライクオブジェクトの属性 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()
clear()
また、以下のメソッドを持ちます:
flush()
現在のセッションデータをデータベースから削除し、後でクッキーに入れて ユーザに送り返すために新たなセッションキーを生成します。ユーザの使っ ているブラウザに、以前のセッションデータにアクセスさせたくない場合に 使います (例えば django.contrib.auth.logout() で呼び出されます)。
set_test_cookie()
テストクッキーを設定して、ユーザのブラウザがクッキーをサポートしてい るかどうかを調べられるようにします。クッキーの動作仕様上、次にブラウ ザがリクエストを送信してくるまでテストは行えません。詳しくは後述の 「 テストクッキーを設定する 」を参照してください。
test_cookie_worked()
ユーザのブラウザがテストクッキーを受け入れたかどうかに応じて True または False を返します。クッキーの動作仕様上、あらかじめ別のペー ジリクエストで set_test_cookie() を呼び出しておかねばなりません。 後述の「 テストクッキーを設定する 」を参照してください。
delete_test_cookie()
テストクッキーを削除します。後始末に使って下さい。
set_expiry(value)
セッションの有効期限をセットします。渡せる値には、以下のバリエーショ ンがあります:
get_expiry_age()
セッションの有効期限が切れるまでの秒数を返します。セッションの有効期 限をカスタマイズしていない場合 (またはブラウザを閉じるまでを有効期限 としている場合) は、 settings.SESSION_COOKIE_AGE と等しい値です。
get_expiry_date()
セッションの有効期限が切れるまでの日数を返します。セッションの有効期 限をカスタマイズしていない場合 (またはブラウザを閉じるまでを有効期限 としている場合) は、 settings.SESSION_COOKIE_AGE 秒に相当する日数 です。
get_expire_at_browser_close()
ユーザのセッションクッキーの有効期限がブラウザを閉じるまでに設定され ていれば True を、そうでなければ False を返します。
request.session はビューのどこで変更しても、何度変更してもかまいません。
以下の簡単なビューの例では、ユーザがコメントをポストした後に 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.contrib.auth.logout() は、うっかりデータが漏洩 してしまうのを防ぐために、 request.session.flush() を呼び出しています。 上の例はセッションオブジェクトの仕組みを説明するためのもので、完全な logout() の実装ではありません。
利便性のために、 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')
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 はブラウ ザアクセス単位のクッキー、すなわちユーザがブラウザを閉じると有効期限が切れ るようなクッキーを使うようになります。ブラウザを起動するたびにユーザにログ イン操作を行わせたい場合、この設定を使ってください。
この設定は、グローバルに有効なデフォルト値です。 「 ビューの外でセッションを使う 」の節で解説した、 request.session.set_expiry() を使えば、セッション単位で有効期限をオーバ ライドできます。
セッションデータは django_session データベーステーブル上に蓄積されます が、 Django はセッションテーブルを自動的に清掃 しません。 つまり、期限切 れの (expired) セッションデータを正しい判断基準の下に削除するのは、アプリケー ション開発者であるあなた自身の仕事なのです。
この問題を理解するには、ユーザがセッションを使ったときに何が起きているかを 考える必要があります。ユーザがログインすると、 Django は django_session データベーステーブルにレコードを 1 行追加します。セッションデータが変更され る度に、このレコード行は更新されてゆきます。ユーザが手動でログアウトすれば、 レコード行は削除されますが、ユーザがログアウト操作を しなかった場合 には、 レコード行は削除されません。
Django は、クリーンアップ用のアクション、 django-admin.py cleanup を提 供しています。このスクリプトはセッションテーブルの全てのエントリの中から、 expire_date の値が過去を指しているものを除去します。もちろん、お使いの アプリケーションが要求する仕様が異なる場合には、別のスクリプトを用意する必 要があるでしょう。
Django 設定ファイル には、セッションの振舞いを操作す るための設定がいくつかあります:
デフォルト値: django.contrib.sessions.backends.db
Django がセッションデータを保存する方法を指定します。利用できる値は以下の通 りです:
詳しくは セッションエンジンの設定 を参照してください。
デフォルト値: /tmp/
ファイルベースのセッションストレージを使っている場合、この値でセッションデー タの保存場所を指定します。
デフォルト値: None
セッションクッキーを使うドメインです。クロスドメインのクッキーを使う場合に は ".lawrence.com" といった値に、通常のドメイン内クッキーの場合には None を指定します。
デフォルト値: False
セッションクッキーにセキュアなクッキーを使うかどうかを決めます。この値を True に設定すると、クッキーは "セキュア" にマークされます。クッキーがセ キュアにマークされると、ブラウザによっては HTTPS 接続でのみクッキーを転送す るようになります。
デフォルト値: False
リクエストごとにセッションデータを保存するかどうかを決めます。この値が False (デフォルト) の場合、セッションデータの保存は内容が変更された場合、 すなわちセッションデータ辞書に値を設定したり、値を削除したりした場合だけに なります。
Django のセッションフレームワークは完全なクッキーベースであり、クッキー以外 の情報を扱いません。従って、 PHP のように URL にセッション ID を入れる方法 を最後の手段に残したりはしていません。これは設計上の意図的な決定です。とい うのも、URL にセッション ID を含めると、みっともない URL になるだけでなく、 "Referer" ヘッダを使ってセッション ID を盗まれるという脆弱性を招くからです。
Aug 31, 2012