.. _topics-http-sessions: =================== セッションの使い方 =================== :revision-up-to: 8961 (1.0) Django では匿名セッション (anonymous session) を完全にサポートしています。 セッションフレームワークを使うと、任意のデータをサイト訪問者単位 (per-site-visitor) で保存したり取得したりできます。セッションフレームワーク はサーバ側にデータを保存し、クッキーの送受信操作を抽象化します。クッキーに はセッション ID だけが保存され、データ自体は送受信されません。 .. _Enabling sessions: セッションを有効にする ====================== セッション機能は :ref:`ミドルウェア ` として実装されていま す。 セッションを有効にするには、以下の作業が必要です: セッション機能をオンオフするには ``MIDDLEWARE_CLASSES`` 設定を編集します。 * ``MIDDLEWARE_CLASSES`` を編集して、 ``'django.contrib.sessions.middleware.SessionMiddleware'`` を入れます。 ``django-admiin.py startproject`` の作成するデフォルトの ``settings.py`` では ``SessionMiddleware`` が有効になっています。 * ``INSTALLED_APPS`` 設定に ``'django.contrib.sessions'`` を入れ、 ``manage.py syncdb`` を実行して、セッションデータを保存するためのデー タベーステーブルを作成します。 .. versionchanged:: 1.0 データベースによるセッションバックエンドを使っていない場合は、このス テップは不要です。 セッション機能を必要としないのなら、 ``MIDDLEWARE_CLASSES`` から ``SessionMiddleware`` の行を削り、 ``INSTALLED_APPS`` からも ``'django.contrib.sessions'`` を削って下さい。セッションを無効にすると、ほ んのわずかだけオーバヘッドを軽減できます。 .. _Configuring the session engine: セッションエンジンの設定 ========================== .. versionadded:: 1.0. デフォルトでは、 Django はセッションをデータベースに (``django.contrib.sessions.models.Session`` モデルを使って) 保存します。こ の仕様は便利ではありますが、場合によっては、データベース以外の場所、ファイ ルシステムやキャッシュ上にセッションデータを保存する方が高速です。 .. _Using file-based sessions: ファイルベースのセッション --------------------------- ファイルベースのセッションを使うには、 ``SESSION_ENGINE`` 設定を ``"django.contrib.sessions.backends.file"`` にします。 また、必要に応じて ``SESSION_FILE_PATH`` も設定してください (デフォルト値は ``tempfile.gettempdir()`` の戻り値で、たいていは ``/tmp`` です)。 Web サー バが ``SESSION_FILE_PATH`` の場所にファイルの読書き権限を持っているか確かめ てください。 .. _Using cache-based sessions: キャッシュベースのセッション ----------------------------- Django のキャッシュシステムにセッションデータを保存するには、 ``SESSION_ENGINE`` に ``"django.contrib.sessions.backends.cache"`` を設定してください。キャッシュを設定済みか確かめてください。詳しくは :ref:`キャッシュのドキュメント ` を参照してください。 .. note:: Memcached をキャッシュバックエンドとして使っているなら、キャッシュベー スのセッションを使うべきです。ローカルメモリ型のキャッシュバックエンド は十分な時間データを保持できないので、よい選択肢とはいえません。また、 ファイルやデータベースによるキャッシュバックエンドを使っている場合、何 もかもをキャッシュに放り込むより、直接ファイルやデータベースからデータ を出力する方がはるかに高速です。 .. _Using sessions in views: ビュー中でセッションを扱う ========================== ``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()`` .. versionadded:: 1.0 ``setdefault()`` と ``clear()`` が追加されました。 また、以下のメソッドを持ちます: * ``flush()`` .. versionadded:: 1.0 現在のセッションデータをデータベースから削除し、後でクッキーに入れて ユーザに送り返すために新たなセッションキーを生成します。ユーザの使っ ているブラウザに、以前のセッションデータにアクセスさせたくない場合に 使います (例えば ``django.contrib.auth.logout()`` で呼び出されます)。 * ``set_test_cookie()`` テストクッキーを設定して、ユーザのブラウザがクッキーをサポートしてい るかどうかを調べられるようにします。クッキーの動作仕様上、次にブラウ ザがリクエストを送信してくるまでテストは行えません。詳しくは後述の 「 `テストクッキーを設定する`_ 」を参照してください。 * ``test_cookie_worked()`` ユーザのブラウザがテストクッキーを受け入れたかどうかに応じて ``True`` または ``False`` を返します。クッキーの動作仕様上、あらかじめ別のペー ジリクエストで ``set_test_cookie()`` を呼び出しておかねばなりません。 後述の「 `テストクッキーを設定する`_ 」を参照してください。 * ``delete_test_cookie()`` テストクッキーを削除します。後始末に使って下さい。 * ``set_expiry(value)`` .. versionadded:: 1.0 セッションの有効期限をセットします。渡せる値には、以下のバリエーショ ンがあります: * ``value`` に整数を渡すと、セッションがアクティブでないまま ``value`` 秒間経った時点で有効期限が切れます。例えば、 ``request.session.set_expiry(300)`` とすると、セッションの有 効期限は 5 分で切れます。 * ``value`` に ``datetime`` や ``timedelta`` オブジェクトを渡す と、セッションの有効期限は指定日・時刻に切れます。 * ``value`` に ``0`` を渡すと、ユーザセッションクッキーの有効期 限は、ブラウザを閉じた時点で切れます。 * ``value`` に ``None`` を渡すと、セッションの有効期限はグロー バルに設定されているセッションポリシーに戻されます。 * ``get_expiry_age()`` .. versionadded:: 1.0 セッションの有効期限が切れるまでの秒数を返します。セッションの有効期 限をカスタマイズしていない場合 (またはブラウザを閉じるまでを有効期限 としている場合) は、 ``settings.SESSION_COOKIE_AGE`` と等しい値です。 * ``get_expiry_date()`` .. versionadded:: 1.0 セッションの有効期限が切れるまでの日数を返します。セッションの有効期 限をカスタマイズしていない場合 (またはブラウザを閉じるまでを有効期限 としている場合) は、 ``settings.SESSION_COOKIE_AGE`` 秒に相当する日数 です。 * ``get_expire_at_browser_close()`` .. versionadded:: 1.0 ユーザのセッションクッキーの有効期限がブラウザを閉じるまでに設定され ていれば ``True`` を、そうでなければ ``False`` を返します。 ``request.session`` はビューのどこで変更しても、何度変更してもかまいません。 .. _Session object guidelines: セッションオブジェクト使用上のガイドライン ------------------------------------------ * ``request.session`` のキーには通常の Python 文字列を使って下さい。と はいえ、これは厳格な掟 (hard-and-fast rule) ではなく単なる規約です。 * アンダースコアで始まるセッション辞書のキーは Django の内部使用のため に予約されています。 * ``request.session`` を新たなオブジェクトでオーバライドしたり、属性を いじってはなりません。Python 辞書型のように扱って下さい。 .. Examples: 使用例 -------- 以下の簡単なビューの例では、ユーザがコメントをポストした後に ``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()`` の実装ではありません。 .. _Setting test cookies: テストクッキーを設定する ======================== 利便性のために、 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') .. _Using sessions out of views: ビューの外でセッションを使う ============================ .. versionadded:: 1.0 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} .. _When sessions are saved: セッションはいつ保存されるのか ============================== デフォルトでは、 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`` 部分もセッションクッキーの送信ごと に更新されます。 .. _Browser-length sessions v persistent sessions: ブラウザアクセス単位のセッションと永続的セッション ================================================== ``SESSION_EXPIRE_AT_BROWSER_CLOSE`` 設定を使うと、セッションフレームワーク に、ブラウザアクセス単位のセッションと永続的セッションのどちらを使わせるか を指定できます。 デフォルトでは、 ``SESSION_EXPIRE_AT_BROWSER_CLOSE`` は ``False`` に設定さ れています。これはセッションクッキーが ``SESSION_COOKIE_AGE`` の間だけブラ ウザに保存されることを示します。ユーザがブラウザを起動するたびにログインし なくてもすむようにしたければ、この設定を使ってください。 ``SESSION_EXPIRE_AT_BROWSER_CLOSE`` を ``True`` にすると、 Django はブラウ ザアクセス単位のクッキー、すなわちユーザがブラウザを閉じると有効期限が切れ るようなクッキーを使うようになります。ブラウザを起動するたびにユーザにログ イン操作を行わせたい場合、この設定を使ってください。 .. versionadded:: 1.0 この設定は、グローバルに有効なデフォルト値です。 「 `ビューの外でセッションを使う`_ 」の節で解説した、 ``request.session.set_expiry()`` を使えば、セッション単位で有効期限をオーバ ライドできます。 .. _Clearing the session table: セッションテーブルの消去 ======================== セッションデータは ``django_session`` データベーステーブル上に蓄積されます が、 Django はセッションテーブルを自動的に清掃 *しません。* つまり、期限切 れの (expired) セッションデータを正しい判断基準の下に削除するのは、アプリケー ション開発者であるあなた自身の仕事なのです。 この問題を理解するには、ユーザがセッションを使ったときに何が起きているかを 考える必要があります。ユーザがログインすると、 Django は ``django_session`` データベーステーブルにレコードを 1 行追加します。セッションデータが変更され る度に、このレコード行は更新されてゆきます。ユーザが手動でログアウトすれば、 レコード行は削除されますが、ユーザがログアウト操作を *しなかった場合* には、 レコード行は削除されません。 Django は、クリーンアップ用のアクション、 ``django-admin.py cleanup`` を提 供しています。このスクリプトはセッションテーブルの全てのエントリの中から、 ``expire_date`` の値が過去を指しているものを除去します。もちろん、お使いの アプリケーションが要求する仕様が異なる場合には、別のスクリプトを用意する必 要があるでしょう。 .. _Settings: 設定 ======== :ref:`Django 設定ファイル ` には、セッションの振舞いを操作す るための設定がいくつかあります: SESSION_ENGINE -------------- .. versionadded:: 1.0 デフォルト値: ``django.contrib.sessions.backends.db`` Django がセッションデータを保存する方法を指定します。利用できる値は以下の通 りです: * ``'django.contrib.sessions.backends.db'`` * ``'django.contrib.sessions.backends.file'`` * ``'django.contrib.sessions.backends.cache'`` 詳しくは `セッションエンジンの設定`_ を参照してください。 SESSION_FILE_PATH ----------------- .. versionadded:: 1.0 デフォルト値: ``/tmp/`` ファイルベースのセッションストレージを使っている場合、この値でセッションデー タの保存場所を指定します。 SESSION_COOKIE_AGE ------------------ デフォルト値: ``1209600`` (秒単位で 2 週間) セッションクッキーの寿命を秒で表したものです。 SESSION_COOKIE_DOMAIN --------------------- デフォルト値: ``None`` セッションクッキーを使うドメインです。クロスドメインのクッキーを使う場合に は ``".lawrence.com"`` といった値に、通常のドメイン内クッキーの場合には ``None`` を指定します。 SESSION_COOKIE_NAME ------------------- Default: ``'sessionid'`` セッションに使うクッキーの名前です。どんな名前にしてもかまいません。 SESSION_COOKIE_SECURE --------------------- デフォルト値: ``False`` セッションクッキーにセキュアなクッキーを使うかどうかを決めます。この値を ``True`` に設定すると、クッキーは "セキュア" にマークされます。クッキーがセ キュアにマークされると、ブラウザによっては HTTPS 接続でのみクッキーを転送す るようになります。 SESSION_EXPIRE_AT_BROWSER_CLOSE ------------------------------- Default: ``False`` ブラウザを閉じたときにセッションを期限切れにするかどうかを決めます。 SESSION_SAVE_EVERY_REQUEST -------------------------- デフォルト値: ``False`` リクエストごとにセッションデータを保存するかどうかを決めます。この値が ``False`` (デフォルト) の場合、セッションデータの保存は内容が変更された場合、 すなわちセッションデータ辞書に値を設定したり、値を削除したりした場合だけに なります。 .. _`Django 設定ファイル`: ../settings/ .. _Django settings: ../settings/ .. _Technical details: 技術的な詳細 ============ * セッション辞書には pickle 化可能な全てのオブジェクトを使えます。詳し くは `pickle モジュールのドキュメント`_ を参照してください。 * セッション情報は ``django_session`` という名前のデータベーステーブルに 保存されます。 * Django は必要なときにしかクッキーを送信しません。従って、セッション情 報を設定しない限り、セッションクッキーの送信を行いません。 .. _`pickle モジュールのドキュメント`: http://www.python.jp/doc/nightly/lib/module-pickle.html .. _`the pickle module`: http://www.python.org/doc/current/lib/module-pickle.html .. _Session IDs in URLs: URL と Session ID ================= Django のセッションフレームワークは完全なクッキーベースであり、クッキー以外 の情報を扱いません。従って、 PHP のように URL にセッション ID を入れる方法 を最後の手段に残したりはしていません。これは設計上の意図的な決定です。とい うのも、URL にセッション ID を含めると、みっともない URL になるだけでなく、 "Referer" ヘッダを使ってセッション ID を盗まれるという脆弱性を招くからです。