Django v1.0 documentation

セッションの使い方

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 を実行して、セッションデータを保存するためのデー タベーステーブルを作成します。

    Django 1.0 で変更されました.

    データベースによるセッションバックエンドを使っていない場合は、このス テップは不要です。

セッション機能を必要としないのなら、 MIDDLEWARE_CLASSES から SessionMiddleware の行を削り、 INSTALLED_APPS からも 'django.contrib.sessions' を削って下さい。セッションを無効にすると、ほ んのわずかだけオーバヘッドを軽減できます。

セッションエンジンの設定

Django 1.0. で新たに登場しました.

デフォルトでは、 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()

Django 1.0 で新たに登場しました: setdefault()clear() が追加されました。

また、以下のメソッドを持ちます:

  • flush()

    Django 1.0 で新たに登場しました.

    現在のセッションデータをデータベースから削除し、後でクッキーに入れて ユーザに送り返すために新たなセッションキーを生成します。ユーザの使っ ているブラウザに、以前のセッションデータにアクセスさせたくない場合に 使います (例えば django.contrib.auth.logout() で呼び出されます)。

  • set_test_cookie()

    テストクッキーを設定して、ユーザのブラウザがクッキーをサポートしてい るかどうかを調べられるようにします。クッキーの動作仕様上、次にブラウ ザがリクエストを送信してくるまでテストは行えません。詳しくは後述の 「 テストクッキーを設定する 」を参照してください。

  • test_cookie_worked()

    ユーザのブラウザがテストクッキーを受け入れたかどうかに応じて True または False を返します。クッキーの動作仕様上、あらかじめ別のペー ジリクエストで set_test_cookie() を呼び出しておかねばなりません。 後述の「 テストクッキーを設定する 」を参照してください。

  • delete_test_cookie()

    テストクッキーを削除します。後始末に使って下さい。

  • set_expiry(value)

    Django 1.0 で新たに登場しました.

    セッションの有効期限をセットします。渡せる値には、以下のバリエーショ ンがあります:

    • value に整数を渡すと、セッションがアクティブでないまま value 秒間経った時点で有効期限が切れます。例えば、 request.session.set_expiry(300) とすると、セッションの有 効期限は 5 分で切れます。
    • valuedatetimetimedelta オブジェクトを渡す と、セッションの有効期限は指定日・時刻に切れます。
    • value0 を渡すと、ユーザセッションクッキーの有効期 限は、ブラウザを閉じた時点で切れます。
    • valueNone を渡すと、セッションの有効期限はグロー バルに設定されているセッションポリシーに戻されます。
  • get_expiry_age()

    Django 1.0 で新たに登場しました.

    セッションの有効期限が切れるまでの秒数を返します。セッションの有効期 限をカスタマイズしていない場合 (またはブラウザを閉じるまでを有効期限 としている場合) は、 settings.SESSION_COOKIE_AGE と等しい値です。

  • get_expiry_date()

    Django 1.0 で新たに登場しました.

    セッションの有効期限が切れるまでの日数を返します。セッションの有効期 限をカスタマイズしていない場合 (またはブラウザを閉じるまでを有効期限 としている場合) は、 settings.SESSION_COOKIE_AGE 秒に相当する日数 です。

  • get_expire_at_browser_close()

    Django 1.0 で新たに登場しました.

    ユーザのセッションクッキーの有効期限がブラウザを閉じるまでに設定され ていれば True を、そうでなければ False を返します。

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.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')

ビューの外でセッションを使う

Django 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}

セッションはいつ保存されるのか

デフォルトでは、 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_REQUESTTrue にすると、 Django はリクエスト一つ一つに対してセッションを保存します。

セッションクッキーはセッションが作成されたり変更されたりした場合にのみ送信 されることに注意してください。 SESSION_SAVE_EVERY_REQUESTTrue にすると、リクエストごとに必ずセッションクッキーを送信するようになります。

同様に、セッションクッキーの expires 部分もセッションクッキーの送信ごと に更新されます。

ブラウザアクセス単位のセッションと永続的セッション

SESSION_EXPIRE_AT_BROWSER_CLOSE 設定を使うと、セッションフレームワーク に、ブラウザアクセス単位のセッションと永続的セッションのどちらを使わせるか を指定できます。

デフォルトでは、 SESSION_EXPIRE_AT_BROWSER_CLOSEFalse に設定さ れています。これはセッションクッキーが SESSION_COOKIE_AGE の間だけブラ ウザに保存されることを示します。ユーザがブラウザを起動するたびにログインし なくてもすむようにしたければ、この設定を使ってください。

SESSION_EXPIRE_AT_BROWSER_CLOSETrue にすると、 Django はブラウ ザアクセス単位のクッキー、すなわちユーザがブラウザを閉じると有効期限が切れ るようなクッキーを使うようになります。ブラウザを起動するたびにユーザにログ イン操作を行わせたい場合、この設定を使ってください。

Django 1.0 で新たに登場しました.

この設定は、グローバルに有効なデフォルト値です。 「 ビューの外でセッションを使う 」の節で解説した、 request.session.set_expiry() を使えば、セッション単位で有効期限をオーバ ライドできます。

セッションテーブルの消去

セッションデータは django_session データベーステーブル上に蓄積されます が、 Django はセッションテーブルを自動的に清掃 しません。 つまり、期限切 れの (expired) セッションデータを正しい判断基準の下に削除するのは、アプリケー ション開発者であるあなた自身の仕事なのです。

この問題を理解するには、ユーザがセッションを使ったときに何が起きているかを 考える必要があります。ユーザがログインすると、 Django は django_session データベーステーブルにレコードを 1 行追加します。セッションデータが変更され る度に、このレコード行は更新されてゆきます。ユーザが手動でログアウトすれば、 レコード行は削除されますが、ユーザがログアウト操作を しなかった場合 には、 レコード行は削除されません。

Django は、クリーンアップ用のアクション、 django-admin.py cleanup を提 供しています。このスクリプトはセッションテーブルの全てのエントリの中から、 expire_date の値が過去を指しているものを除去します。もちろん、お使いの アプリケーションが要求する仕様が異なる場合には、別のスクリプトを用意する必 要があるでしょう。

設定

Django 設定ファイル には、セッションの振舞いを操作す るための設定がいくつかあります:

SESSION_ENGINE

Django 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

Django 1.0 で新たに登場しました.

デフォルト値: /tmp/

ファイルベースのセッションストレージを使っている場合、この値でセッションデー タの保存場所を指定します。

SESSION_EXPIRE_AT_BROWSER_CLOSE

Default: False

ブラウザを閉じたときにセッションを期限切れにするかどうかを決めます。

SESSION_SAVE_EVERY_REQUEST

デフォルト値: False

リクエストごとにセッションデータを保存するかどうかを決めます。この値が False (デフォルト) の場合、セッションデータの保存は内容が変更された場合、 すなわちセッションデータ辞書に値を設定したり、値を削除したりした場合だけに なります。

技術的な詳細

  • セッション辞書には pickle 化可能な全てのオブジェクトを使えます。詳し くは pickle モジュールのドキュメント を参照してください。
  • セッション情報は django_session という名前のデータベーステーブルに 保存されます。
  • Django は必要なときにしかクッキーを送信しません。従って、セッション情 報を設定しない限り、セッションクッキーの送信を行いません。

URL と Session ID

Django のセッションフレームワークは完全なクッキーベースであり、クッキー以外 の情報を扱いません。従って、 PHP のように URL にセッション ID を入れる方法 を最後の手段に残したりはしていません。これは設計上の意図的な決定です。とい うのも、URL にセッション ID を含めると、みっともない URL になるだけでなく、 "Referer" ヘッダを使ってセッション ID を盗まれるという脆弱性を招くからです。