---
title: "セッションの使いかた"
version: 4.2
locale: ja
source: https://docs.djangoproject.com/ja/4.2/topics/http/sessions/
canonical: https://djangodocs.dev/ja/4.2/topics/http/sessions/
---
# セッションの使いかた

Django は、匿名のセッションをフルサポートしています。このセッションフレームワークを使えば、任意のデータを、サイトの訪問者ごとに保存し、取得することができます。データはサーバー側に保存され、クッキーの送受信によって抽象化します。クッキーには、データそのものではなくセッション ID が書かれています ( [クッキーベースのバックエンド](#cookie-session-backend) を使用しない限り)。

## セッションを有効にする

セッションは、 [ミドルウェア](/ja/4.2/ref/middleware/) の1つを使って実装されています。

セッションの機能を有効にするには、次のように設定を行います。

- [`MIDDLEWARE`](/ja/4.2/ref/settings/#std-setting-MIDDLEWARE) 設定を編集し `'django.contrib.sessions.middleware.SessionMiddleware'` を含むようにする。 `django-admin startproject` で作られるデフォルトの `settings.py` は `SessionMiddleware` が有効化されています。

セッションを使いたくない場合は、 [`MIDDLEWARE`](/ja/4.2/ref/settings/#std-setting-MIDDLEWARE) 内の `SessionMiddleware` 行と [`INSTALLED_APPS`](/ja/4.2/ref/settings/#std-setting-INSTALLED_APPS) 内の `'django.contrib.sessions'` を削除しても構いません。これで、オーバーヘッドが少しだけ短縮されます。

## セッションエンジンを設定する

デフォルトでは、Django はセッションを、(`django.contrib.sessions.models.Session` モデルを用いて) データベースに保存します。これは便利ですが、セットアップによってはセッションのデータを他の場所においたほうが高速化できる場合があります。そのため、Django はセッションデータをファイルシステムやキャッシュに保存するように設定することができます。

### データベースを使ったセッション

データベースを使った (database-backed) セッションを使いたい場合には、設定ファイルの [`INSTALLED_APPS`](/ja/4.2/ref/settings/#std-setting-INSTALLED_APPS)  に `'django.contrib.sessions'` を追加する必要があります。

一度インストールの設定をすれば、`manage.py migrate` を実行することで、セッションデータを保存する1つのデータベーステーブルをインストールできます。

### キャッシュを使ったセッション

よいパフォーマンスを発揮するには、キャッシュを使ったセッションバックエンドを利用した方が良いかもしれません。

Django のキャッシュシステムを使ってセッションデータを保存するには、まず初めに、キャッシュの設定を済ませておく必要があります。詳しくは、 [キャッシュのドキュメンテーション](/ja/4.2/topics/cache/) を読んでください。

> **Warning**
>
> キャッシュを使ったセッションを用いるのは、Memcached または Redis キャッシュバックエンドを使用している場合だけにするべきです。ローカルなメモリキャッシュバックエンドを使用している場合、長時間データをメモリ上に保持しておくのは良い考えではありませんし、全てのデータをファイルやデータベースキャッシュバックエンドを通して送信するよりも、ファイルやデータベースに保存されたセッションから直接送信した方が高速だからです。加えて、ローカルなメモリキャッシュバックエンドは、マルチプロセスに対して安全「ではありません」。したがって、実環境ではあまり良い選択とは言えないでしょう。

設定ファイルの [`CACHES`](/ja/4.2/ref/settings/#std-setting-CACHES) で複数のキャッシュを定義している場合、Django はデフォルトのキャッシュを使用します。他のキャッシュを使用するには、[`SESSION_CACHE_ALIAS`](/ja/4.2/ref/settings/#std-setting-SESSION_CACHE_ALIAS) を使用したいキャッシュの名前に変更します。

一度キャッシュが設定されると、データベース ベースのキャッシュ(database-backed cache) か非永続キャッシュ (non-persistent cache) のどちらかを選択する必要があります。

The cached database backend (`cached_db`) uses a write-through cache --
session writes are applied to both the cache and the database. Session reads
use the cache, or the database if the data has been evicted from the cache. To
use this backend, set [`SESSION_ENGINE`](/ja/4.2/ref/settings/#std-setting-SESSION_ENGINE) to
`"django.contrib.sessions.backends.cached_db"`, and follow the configuration
instructions for the [using database-backed sessions](#using-database-backed-sessions).

The cache backend (`cache`) stores session data only in your cache. This is
faster because it avoids database persistence, but you will have to consider
what happens when cache data is evicted. Eviction can occur if the cache fills
up or the cache server is restarted, and it will mean session data is lost,
including logging out users. To use this backend, set [`SESSION_ENGINE`](/ja/4.2/ref/settings/#std-setting-SESSION_ENGINE)
to `"django.contrib.sessions.backends.cache"`.

The cache backend can be made persistent by using a persistent cache, such as
Redis with appropriate configuration. But unless your cache is definitely
configured for sufficient persistence, opt for the cached database backend.
This avoids edge cases caused by unreliable data storage in production.

### ファイルを使ったセッション

ファイルを使ったセッションを使用するには、[`SESSION_ENGINE`](/ja/4.2/ref/settings/#std-setting-SESSION_ENGINE) を `"django.contrib.sessions.backends.file"` に設定します。

Django がセッションファイルを保存する場所を設定したい場合には、[`SESSION_FILE_PATH`](/ja/4.2/ref/settings/#std-setting-SESSION_FILE_PATH) を設定します (出力先のデフォルト値は、`tempfile.gettempdir()`、普通は `/tmp` になっています)。ウェブサーバが設定した場所の読み書きの権限を持っていることを確認しておいてください。

### クッキーを使ったセッション

クッキーを使ったセッションを使用するには、 [`SESSION_ENGINE`](/ja/4.2/ref/settings/#std-setting-SESSION_ENGINE) を `"django.contrib.sessions.backends.signed_cookies"` に設定します。セッションデータは、 [暗号化署名](/ja/4.2/topics/signing/) のための Django のツールと [`SECRET_KEY`](/ja/4.2/ref/settings/#std-setting-SECRET_KEY) を使って保存されます。

> **Note**
>
> 保存されたデータに JavaScript からアクセスできないように、[`SESSION_COOKIE_HTTPONLY`](/ja/4.2/ref/settings/#std-setting-SESSION_COOKIE_HTTPONLY) を `True` に設定しておくことをおすすめします。

> **Warning**
>
> `SECRET_KEY` **または** `SECRET_KEY_FALLBACKS` **が知られてしまい、** [`PickleSerializer`](#django.contrib.sessions.serializers.PickleSerializer) **を使用していた場合、任意のリモートコードが実行可能になってしまいます。**
>
> [`SECRET_KEY`](/ja/4.2/ref/settings/#std-setting-SECRET_KEY) または [`SECRET_KEY_FALLBACKS`](/ja/4.2/ref/settings/#std-setting-SECRET_KEY_FALLBACKS) を知っている攻撃者は、偽造したセッションデータを生成して Django のサイトを騙すことができるのみならず、pickle を使ってシリアライズしたデータを送ることで、リモートから任意のコードを実行できてしまいます。
>
> クッキーを使ったセッションを使うときには、リモートからアクセスできるいかなるシステムに対しても秘密鍵が絶対に外に漏れないように、細心の注意を払ってください。
>
> **このセッションデータは、署名はされていますが、暗号化はされていません。**
>
> クッキーバックエンドを使う時には、セッションデータはクライアントが自由に読むことができます。
>
> MAC (Message Authentication Code; メッセージ認証コード) を使っているので、たとえクライアントがデータを勝手に書き変えてしまったとしても、書き換えられたセッションデータは無効と判定されます。しかし、たとえばミューザのブラウザが保存しているクッキーを保存できたとしても、セッションクッキーのデータがすべて保存できず、データの一部が失われることがあり、この場合にもセッションデータは無効となってしまいます。Django はデータを圧縮しますが、それでもデータのサイズが1クッキーごとの  一般的な制限の 4096 バイト \<2965#section-5.3\> を超えてしまうことは十分に考えられることです。
>
> **情報が最新であることが保証されません**
>
> MAC のおかげで、データの認証性 (データが他のサイトではなく、確実に自分のサイトで作られたものであること) と、完全性 (データが存在し、データが正しいこと) は保証されますが、そのデータが最新のものであることは保証することができません。つまり、クライアントからデータを受け取ったとしても、そのデータがユーザに最後に送った最新のデータであることは保証できないのです。ということは、セッションデータの使い方によっては、クッキーバックエンドでは  [replay attacks](https://en.wikipedia.org/wiki/Replay_attack) ができてしまうことになります。他のセッションバックエンドでは、サーバー側に各セッションの記録が残るので、ユーザがログアウトした時にそれを無効化できますが、クッキーを使ったセッションの場合には、ユーザがログアウトしてもセッションは無効化されません。したがって、攻撃者がユーザのクッキーを盗めば、たとえユーザがログアウトしていたとしても、そのクッキーを使ってユーザになりすますことができてしまいます。クッキーが「古くなった」と判断できるのは、[`SESSION_COOKIE_AGE`](/ja/4.2/ref/settings/#std-setting-SESSION_COOKIE_AGE) を過ぎた場合だけだからです。
>
> **パフォーマンス**
>
> 最後に、クッキーのサイズが大きくなると、サイトの速度にも大きな影響があります。

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

`SessionMiddleware` を有効にすれば、それぞれの [`HttpRequest`](/ja/4.2/ref/request-response/#django.http.HttpRequest) オブジェクト――Django のビュー関数に渡される最初の引数――は、ディクショナリライクなオブジェクトの `session` 属性を持つようになります。

この `request.session` には、ビューの好きな場所で、何度でも、読み書きを行うことができます。

#### `class backends.base.SessionBase`

このオブジェクトは、すべてのセッションオブジェクトのベースクラスとなっているので、以下に挙げるような基本的なディクショナリのメソッドを持っています。

#### `__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')`

#### `pop(key, default=__not_given)`

例: `fav_color = request.session.pop('fav_color', 'blue')`

#### `keys()`

#### `items()`

#### `setdefault()`

#### `clear()`

また、次のようなメソッドも利用できます。

#### `flush()`

セッションから現在のセッションデータを削除し、セッションクッキーを削除します。このメソッドは、前回のセッションデータがユーザのブラウザから再びアクセスされないようにするためなどに使います (たとえば、[`django.contrib.auth.logout()`](/ja/4.2/topics/auth/default/#django.contrib.auth.logout) がこの関数を呼びます)。

#### `set_test_cookie()`

ユーザのブラウザがクッキーをサポートしているかどうか判定するために、テスト用のクッキーをセットします。クッキーの動作原理により、ユーザが次のページへのリクエストを行わないとこのテストは行えません。詳しい情報については、下の [Setting test cookies](#setting-test-cookies) を読んでください。

#### `test_cookie_worked()`

ユーザのブラウザがテストクッキーを正しく保存したかどうかに応じて、`True` または `False` を返します。クッキーの動作原理により、あらかじめ別のページのリクエストとして `set_test_cookie()` を呼び出しておく必要があります。詳しい情報については、下の [Setting test cookies](#setting-test-cookies) を読んでください。

#### `delete_test_cookie()`

テストクッキーを削除します。クッキーをきれいにしておくために使ってください。

#### `get_session_cookie_age()`

[`SESSION_COOKIE_AGE`](/ja/4.2/ref/settings/#std-setting-SESSION_COOKIE_AGE) の設定値を返す。これはカスタム セッション バックエンドで上書きできる。

#### `set_expiry(value)`

セッションの有効期限を設定します。以下に挙げるようなさまざまな値を与えることができます。

- もし `value` が整数なら、与えられた秒数だけ活動がなかった時にセッションを破棄します。たとえば、`request.session.set_expiry(300)` と呼び出せば、5分後にセッションを破棄するように設定できます。
- If `value` is a `datetime` or `timedelta` object, the session
  will expire at that specific date/time.
- If `value` is `0`, the user's session cookie will expire
  when the user's web browser is closed.
- もし `value` が `None` ならば、セッションはグローバルなセッション有効期限ポリシーにしたがって扱われます。

セッションの読み込みを行っても、有効期限は延長されません。セッションの有効期限は、セッションが最後に\*修正された\*時点を基に計算されます。

#### `get_expiry_age()`

このセッションの有効期限までの残りの秒数を返します。カスタムの有効期限を持たない (または、ブラウザを閉じた時とセットした) セッションの場合、この値は [`SESSION_COOKIE_AGE`](/ja/4.2/ref/settings/#std-setting-SESSION_COOKIE_AGE) と等しいです。

この関数は 2 つの省略可能なキーワード引数を取ることができます。

- `modification`: セッションを最後に修正した時刻を [`datetime`](https://docs.python.org/3/library/datetime.html#datetime.datetime) オブジェクトとして与える。デフォルトは現在の時刻。
- `expiry`: セッションの有効期限の情報を [`datetime`](https://docs.python.org/3/library/datetime.html#datetime.datetime) オブジェクト、[`int`](https://docs.python.org/3/library/functions.html#int) (秒数で)、または `None` として与えます。デフォルトの値は、もしあれば、セッションに保存されている [`set_expiry()`](#django.contrib.sessions.backends.base.SessionBase.set_expiry) で得られる値、なければ `None` です。

> **Note**
>
> This method is used by session backends to determine the session expiry
> age in seconds when saving the session. It is not really intended for
> usage outside of that context.
>
> In particular, while it is **possible** to determine the remaining
> lifetime of a session **just when** you have the correct
> `modification` value **and** the `expiry` is set as a `datetime`
> object, where you do have the `modification` value, it is more
> straight-forward to calculate the expiry by-hand:
>
> ```
> expires_at = modification + timedelta(seconds=settings.SESSION_COOKIE_AGE)
> ```

#### `get_expiry_date()`

このセッションが破棄される日付を返します。カスタムの有効期限を持たない (または、ブラウザを閉じた時とセットした) セッションに対しては、現在時刻から [`SESSION_COOKIE_AGE`](/ja/4.2/ref/settings/#std-setting-SESSION_COOKIE_AGE) の秒数までの日付に等しいです。

This function accepts the same keyword arguments as
[`get_expiry_age()`](#django.contrib.sessions.backends.base.SessionBase.get_expiry_age), and similar notes on usage apply.

#### `get_expire_at_browser_close()`

Returns either `True` or `False`, depending on whether the user's
session cookie will expire when the user's web browser is closed.

#### `clear_expired()`

保存されているセッションから、有効期限が切れているものを削除します。このクラスメソッドは、[`clearsessions`](/ja/4.2/ref/django-admin/#django-admin-clearsessions) から呼び出されます。

#### `cycle_key()`

現在のセッションデータを保持したまま、新しいセッションキーを作成します。[`django.contrib.auth.login()`](/ja/4.2/topics/auth/default/#django.contrib.auth.login) は、このメソッドを呼び出すことで、過去のセッションを継続できるようにしています。

### セッションのシリアライズ

デフォルトでは、Django はセッションデータを JSON を用いてシリアライズします。設定ファイルの [`SESSION_SERIALIZER`](/ja/4.2/ref/settings/#std-setting-SESSION_SERIALIZER) に設定すれば、セッションをシリアライズするフォーマットをカスカムできます。 [自作のシリアライザを書く](#custom-serializers) に書いた注意書きの通り、JSON によるシリアライズを強く推奨します。 *クッキーバックエンドを利用している場合は特に* です。

For example, here's an attack scenario if you use [`pickle`](https://docs.python.org/3/library/pickle.html#module-pickle) to serialize
session data. If you're using the [signed cookie session backend](#cookie-session-backend) and [`SECRET_KEY`](/ja/4.2/ref/settings/#std-setting-SECRET_KEY) (or any key of
[`SECRET_KEY_FALLBACKS`](/ja/4.2/ref/settings/#std-setting-SECRET_KEY_FALLBACKS)) is known by an attacker (there isn't an
inherent vulnerability in Django that would cause it to leak), the attacker
could insert a string into their session which, when unpickled, executes
arbitrary code on the server. The technique for doing so is simple and easily
available on the internet. Although the cookie session storage signs the
cookie-stored data to prevent tampering, a [`SECRET_KEY`](/ja/4.2/ref/settings/#std-setting-SECRET_KEY) leak
immediately escalates to a remote code execution vulnerability.

#### バンドルされているシリアライザ

#### `class serializers.JSONSerializer`

[`django.core.signing`](/ja/4.2/topics/signing/#module-django.core.signing) の JSON シリアライザのラッパーです。基本的なデータ型だけがシリアライズ可能です。

In addition, as JSON supports only string keys, note that using non-string
keys in `request.session` won't work as expected:

```pycon
>>> # initial assignment
>>> request.session[0] = "bar"
>>> # subsequent requests following serialization & deserialization
>>> # of session data
>>> request.session[0]  # KeyError
>>> request.session["0"]
'bar'
```

Similarly, data that can't be encoded in JSON, such as non-UTF8 bytes like
`'\xd9'` (which raises [`UnicodeDecodeError`](https://docs.python.org/3/library/exceptions.html#UnicodeDecodeError)), can't be stored.

JSON によるシリアライズの制限について詳しくは、[自作のシリアライザを書く](#custom-serializers) セクションを読んでください。

#### `class serializers.PickleSerializer`

Supports arbitrary Python objects, but, as described above, can lead to a
remote code execution vulnerability if [`SECRET_KEY`](/ja/4.2/ref/settings/#std-setting-SECRET_KEY) or any key of
[`SECRET_KEY_FALLBACKS`](/ja/4.2/ref/settings/#std-setting-SECRET_KEY_FALLBACKS) becomes known by an attacker.

> **Deprecated since Django 4.1**
>
> バージョン 4.1 で非推奨: Due to the risk of remote code execution, this serializer is deprecated
> and will be removed in Django 5.0.

#### 自作のシリアライザを書く

Note that the [`JSONSerializer`](#django.contrib.sessions.serializers.JSONSerializer)
cannot handle arbitrary Python data types. As is often the case, there is a
trade-off between convenience and security. If you wish to store more advanced
data types including `datetime` and `Decimal` in JSON backed sessions, you
will need to write a custom serializer (or convert such values to a JSON
serializable object before storing them in `request.session`). While
serializing these values is often straightforward
([`DjangoJSONEncoder`](/ja/4.2/topics/serialization/#django.core.serializers.json.DjangoJSONEncoder) may be helpful),
writing a decoder that can reliably get back the same thing that you put in is
more fragile. For example, you run the risk of returning a `datetime` that
was actually a string that just happened to be in the same format chosen for
`datetime`s).

シリアライザのクラスは、必ず次の2つのメソッドを実装しなければなりません。セッションデータのディクショナリをシリアライズする `dumps(self, obj)` と、それをデシリアライズする `loads(self, data)` の2つです。

### セッションオブジェクトのガイドライン

- Python の普通の文字列を、`request.session` におけるディクショナリのキーとして使うこと。これは慣習のためというよりも、確実で高速にするためのルールです。
- セッションのディクショナリのキーで、アンダースコアで始まるキーは、Django が内部で使用するために予約されているものと考えること。
- `request.session` を新しいオブジェクトで上書きせず、その属性にアクセスしたり、値をセットしたりしないこと。Python のディクショナリのように扱うこと。

### 例

次の簡単なビューは、ユーザがコメントを投稿した後で、`has_commented` 変数を `True` に設定します。こうすることで、同じユーザが2回以上コメントできないようにすることができます。

```
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!")
```

次の次の簡単なビューでは、サイトの「メンバー (member)」にログインする手続きを行います。

```
def login(request):
    m = Member.objects.get(username=request.POST["username"])
    if m.check_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()`](/ja/4.2/topics/auth/default/#django.contrib.auth.logout) 関数では、データの意図しない漏洩を防ぐために、この例より少し複雑な処理、`request.session` の [`flush()`](#django.contrib.sessions.backends.base.SessionBase.flush) メソッドを呼び出すなどの処理を行っています。ここで挙げた例は、単にセッションオブジェクトの振る舞いをデモンストレーションすることが目的なので、完全ではない `logout()` を実装しました。

## テストクッキーを設定する

As a convenience, Django provides a way to test whether the user's browser
accepts cookies. Call the [`set_test_cookie()`](#django.contrib.sessions.backends.base.SessionBase.set_test_cookie)
method of `request.session` in a view, and call
[`test_cookie_worked()`](#django.contrib.sessions.backends.base.SessionBase.test_cookie_worked) in a subsequent view --
not in the same view call.

このように `set_test_cookie()` と `test_cookie_worked()` を分離しなければならないのはちょっと気持ち悪いですが、クッキーの動作原理により、こうするより仕方がないのです。一度ブラウザにクッキーを設定しても、そのクッキーがブラウザに保存されたかどうかを確認するには、ブラウザがもう一度リクエストを行わなければならないからです。

テストクッキーがちゃんと機能していることを確認できたら、[`delete_test_cookie()`](#django.contrib.sessions.backends.base.SessionBase.delete_test_cookie) を使ってセッションをきれいにしておくことにしましょう。

以下に、テストクッキーの典型的な使用例を挙げます。

```
from django.http import HttpResponse
from django.shortcuts import render

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(request, "foo/login_form.html")
```

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

> **Note**
>
> このセクションの例では、`SessionStore` オブジェクトを直接 `django.contrib.sessions.backends.db` バックエンドからインポートしています。しかし、実際に自分でコートを書く場合には、以下のようにして、[`SESSION_ENGINE`](/ja/4.2/ref/settings/#std-setting-SESSION_ENGINE) が指すセッションエンジンから `SessionStore` をインポートすることを考えるべきです。
>
> ```pycon
> >>> from importlib import import_module
> >>> from django.conf import settings
> >>> SessionStore = import_module(settings.SESSION_ENGINE).SessionStore
> ```

An API is available to manipulate session data outside of a view:

```pycon
>>> from django.contrib.sessions.backends.db import SessionStore
>>> s = SessionStore()
>>> # stored as seconds since epoch since datetimes are not serializable in JSON.
>>> s["last_login"] = 1376587691
>>> s.create()
>>> s.session_key
'2b1189a188b44ad18c35e113ac6ceead'
>>> s = SessionStore(session_key="2b1189a188b44ad18c35e113ac6ceead")
>>> s["last_login"]
1376587691
```

`SessionStore.create()` is designed to create a new session (i.e. one not
loaded from the session store and with `session_key=None`). `save()` is
designed to save an existing session (i.e. one loaded from the session store).
Calling `save()` on a new session may also work but has a small chance of
generating a `session_key` that collides with an existing one. `create()`
calls `save()` and loops until an unused `session_key` is generated.

If you're using the `django.contrib.sessions.backends.db` backend, each
session is a normal Django model. The `Session` model is defined in
[django/contrib/sessions/models.py](https://github.com/django/django/blob/stable/4.2.x/django/contrib/sessions/models.py). Because it's a normal model, you can
access sessions using the normal Django database API:

```pycon
>>> from django.contrib.sessions.models import Session
>>> s = Session.objects.get(pk="2b1189a188b44ad18c35e113ac6ceead")
>>> s.expire_date
datetime.datetime(2005, 8, 20, 13, 35, 12)
```

Note that you'll need to call
[`get_decoded()`](#django.contrib.sessions.base_session.AbstractBaseSession.get_decoded) to get the session
dictionary. This is necessary because the dictionary is stored in an encoded
format:

```pycon
>>> s.session_data
'KGRwMQpTJ19hdXRoX3VzZXJfaWQnCnAyCkkxCnMuMTExY2ZjODI2Yj...'
>>> s.get_decoded()
{'user_id': 42}
```

## セッションが保存されるタイミング

デフォルトでは、Django がセッションデータベースへデータを保存するのは、セッションが修正された時だけ、つまり、ディクショナリ直下の値が代入または削除された時だけです。

```
# Session is modified.
request.session["foo"] = "bar"

# Session is modified.
del request.session["foo"]

# Session is modified.
request.session["foo"] = {}

# Gotcha: Session is NOT modified, because this alters
# request.session['foo'] instead of request.session.
request.session["foo"]["bar"] = "baz"
```

上の例の場合、セッションオブジェクトに修正したことを明示的に伝えるためには、`modified` 属性を設定すれば良いです。

```
request.session.modified = True
```

このデフォルトの動作を変更するには、設定ファイルの [`SESSION_SAVE_EVERY_REQUEST`](/ja/4.2/ref/settings/#std-setting-SESSION_SAVE_EVERY_REQUEST) を `True` に設定します。`True` に設定すると、Django は1リクエストごとに、セッションをデータベースに保存してくれるようになります。

セッションクッキーが送信されるのは、セッションの作成及び修正時のみであることに注意してください。[`SESSION_SAVE_EVERY_REQUEST`](/ja/4.2/ref/settings/#std-setting-SESSION_SAVE_EVERY_REQUEST) を `True` に設定すると、各リクエストごとにセッションクッキーが送信されるようになります。

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

レスポンスステータスコードが 500 の時には、セッションは保存されません。

## ブラウザ起動中のみ有効なセッション vs. 永続的なセッション

[`SESSION_EXPIRE_AT_BROWSER_CLOSE`](/ja/4.2/ref/settings/#std-setting-SESSION_EXPIRE_AT_BROWSER_CLOSE) 設定を使うと、セッションフレームワークが、ブラウザ起動中のみ有効なセッションと永続的なセッションのどちらを使うか設定できます。

デフォルトでは、[`SESSION_EXPIRE_AT_BROWSER_CLOSE`](/ja/4.2/ref/settings/#std-setting-SESSION_EXPIRE_AT_BROWSER_CLOSE) は `False` にセットされていて、セッションクッキーは [`SESSION_COOKIE_AGE`](/ja/4.2/ref/settings/#std-setting-SESSION_COOKIE_AGE) の期間ユーザのブラウザに保持されます。これにより、ユーザはブラウザを開くたびにログインし直さずに済みます。

[`SESSION_EXPIRE_AT_BROWSER_CLOSE`](/ja/4.2/ref/settings/#std-setting-SESSION_EXPIRE_AT_BROWSER_CLOSE) を `True` に設定すると、Django はブラウザ起動中のみ有効なクッキーを使用します。このクッキーは、ブラウザを閉じた瞬間に破棄されます。ユーザがブラウザを開くたびにログインするようにしたい場合には、この設定を利用してください。

この設定はグローバルなデフォルトですが、1セッションごとのレベルで設定を上書きすることができます。その場合には、上の [using sessions in views](#using-sessions-in-views) で書いたようにして、`request.session` の [`set_expiry()`](#django.contrib.sessions.backends.base.SessionBase.set_expiry) メソッドを呼び出してください。

> **Note**
>
> Some browsers (Chrome, for example) provide settings that allow users to
> continue browsing sessions after closing and reopening the browser. In
> some cases, this can interfere with the
> [`SESSION_EXPIRE_AT_BROWSER_CLOSE`](/ja/4.2/ref/settings/#std-setting-SESSION_EXPIRE_AT_BROWSER_CLOSE) setting and prevent sessions
> from expiring on browser close. Please be aware of this while testing
> Django applications which have the
> [`SESSION_EXPIRE_AT_BROWSER_CLOSE`](/ja/4.2/ref/settings/#std-setting-SESSION_EXPIRE_AT_BROWSER_CLOSE) setting enabled.

## セッションストアのクリア

ユーザがウェブサイトで新しいセッションを作成した時、セッションデータはセッションストアに溜め込まれます。データベースのバックエンドを使っている場合には、`django_session` データベーステーブルが増大し、ファイルバックエンドを使っている場合には、一時ディレクトリのファイル数が増えてゆくでしょう。

この問題を理解するには、データベースバックエンドで起きていることを考えてみてください。ユーザがログインすると、Django は `django_session` データベースのテーブルに1行を追加します。Django はセッションのデータが変更されるたびに、この行を更新します。ユーザが手動でログアウトすると、Django はこの行を削除します。しかし、ユーザがログアウト\*しなかった\*場合には、この行は決して削除されません。同様のプロセスが、ファイルバックエンドの場合にも発生します。

Django は、有効期限の切れたセッションを自動的に削除する機能を提供\*しません\*。したがって、定期的に有効期限の切れたセッションを削除する仕事は、開発者の手に委ねられています。Django はこの目的のために、クリーンナップ用の管理コマンド [`clearsessions`](/ja/4.2/ref/django-admin/#django-admin-clearsessions) を用意しています。たとえば、cron の毎日のジョブに追加するなどの方法で、定期的にこのコマンドを実行することが推奨されています。

キャッシュバックエンドの場合はこの問題が発生しないことに注意してください。キャッシュの場合、不要なデータは自動的に削除されるようになっているからです。しかし、クッキーバックエンドの場合はそうではありません。セッションデータはユーザのブラウザに保存されるからです。

## 設定

以下の [Django の設定](/ja/4.2/ref/settings/#settings-sessions) を使うと、セッションの振る舞いをコントロールすることができます。

- [`SESSION_CACHE_ALIAS`](/ja/4.2/ref/settings/#std-setting-SESSION_CACHE_ALIAS)
- [`SESSION_COOKIE_AGE`](/ja/4.2/ref/settings/#std-setting-SESSION_COOKIE_AGE)
- [`SESSION_COOKIE_DOMAIN`](/ja/4.2/ref/settings/#std-setting-SESSION_COOKIE_DOMAIN)
- [`SESSION_COOKIE_HTTPONLY`](/ja/4.2/ref/settings/#std-setting-SESSION_COOKIE_HTTPONLY)
- [`SESSION_COOKIE_NAME`](/ja/4.2/ref/settings/#std-setting-SESSION_COOKIE_NAME)
- [`SESSION_COOKIE_PATH`](/ja/4.2/ref/settings/#std-setting-SESSION_COOKIE_PATH)
- [`SESSION_COOKIE_SAMESITE`](/ja/4.2/ref/settings/#std-setting-SESSION_COOKIE_SAMESITE)
- [`SESSION_COOKIE_SECURE`](/ja/4.2/ref/settings/#std-setting-SESSION_COOKIE_SECURE)
- [`SESSION_ENGINE`](/ja/4.2/ref/settings/#std-setting-SESSION_ENGINE)
- [`SESSION_EXPIRE_AT_BROWSER_CLOSE`](/ja/4.2/ref/settings/#std-setting-SESSION_EXPIRE_AT_BROWSER_CLOSE)
- [`SESSION_FILE_PATH`](/ja/4.2/ref/settings/#std-setting-SESSION_FILE_PATH)
- [`SESSION_SAVE_EVERY_REQUEST`](/ja/4.2/ref/settings/#std-setting-SESSION_SAVE_EVERY_REQUEST)
- [`SESSION_SERIALIZER`](/ja/4.2/ref/settings/#std-setting-SESSION_SERIALIZER)

## セッションのセキュリティ

サイトのサブドメインからは、クライアントに対して、ドメイン全体に対するクッキーを設定することができます。信頼できるユーザに管理されていないサブドメインから送られたクッキーを許可している場合、この方法で session fixation 攻撃が可能になってしまいます。

For example, an attacker could log into `good.example.com` and get a valid
session for their account. If the attacker has control over `bad.example.com`,
they can use it to send their session key to you since a subdomain is permitted
to set cookies on `*.example.com`. When you visit `good.example.com`,
you'll be logged in as the attacker and might inadvertently enter your
sensitive personal data (e.g. credit card info) into the attacker's account.

Another possible attack would be if `good.example.com` sets its
[`SESSION_COOKIE_DOMAIN`](/ja/4.2/ref/settings/#std-setting-SESSION_COOKIE_DOMAIN) to `"example.com"` which would cause
session cookies from that site to be sent to `bad.example.com`.

## 技術的な詳細

- The session dictionary accepts any [`json`](https://docs.python.org/3/library/json.html#module-json) serializable value when using
  [`JSONSerializer`](#django.contrib.sessions.serializers.JSONSerializer).
- セッションデータは、データベースの `django_session` という名前のテーブルに保存されます。
- Django は必要なときにだけクッキーを送信します。新しくセッションデータを設定しなければ、Django はセッションクッキーを送信しません。

### `SessionStore` オブジェクト

Django が内部でセッションを操作する時は、対応するセッションエンジンの session store オブジェクトを使用します。慣習により、session store オブジェクトは `SessionStore` と名付けられていて、[`SESSION_ENGINE`](/ja/4.2/ref/settings/#std-setting-SESSION_ENGINE) で指定したモジュール内に置かれています。

Django で利用可能なすべての `SessionStore` クラスは、[`SessionBase`](#django.contrib.sessions.backends.base.SessionBase) を継承していて、以下のデータを操作するメソッドを実装しています。

- `exists()`
- `create()`
- `save()`
- `delete()`
- `load()`
- [`clear_expired()`](#django.contrib.sessions.backends.base.SessionBase.clear_expired)

独自のセッションエンジンを作ったり、既存のものをカスタマイズするには、[`SessionBase`](#django.contrib.sessions.backends.base.SessionBase) か既存の `SessionStore` クラスを継承した新しいクラスを作る必要があるでしょう。

You can extend the session engines, but doing so with database-backed session
engines generally requires some extra effort (see the next section for
details).

## データベースを使ったセッションを拡張する

Django に含まれるデータベースを使ったセッションエンジン (具体的に言えば、`db` と `cached_db`) をカスタマイズするには、[`AbstractBaseSession`](#django.contrib.sessions.base_session.AbstractBaseSession) とともに `SessionStore` クラスを継承する必要があるかもしれません。

`AbstractBaseSession` と `BaseSessionManager` は、[`INSTALLED_APPS`](/ja/4.2/ref/settings/#std-setting-INSTALLED_APPS) に `django.contrib.sessions` を追加しなくても、`django.contrib.sessions.base_session` からインポートすることができます。

#### `class base_session.AbstractBaseSession`

ベースとなる抽象的なセッションのモデルです。

#### `session_key`

プライマリーキーです。フィールド自体は40文字までの文字列を格納できますが、現在の実装では、32文字の文字列 (数字と小文字のASCII文字のランダムな列) を生成します。

#### `session_data`

エンコード・シリアライズされた、セッションディクショナリーを含む文字列です。

#### `expire_date`

セッションの有効期限を表す datetime オブジェクトです。

有効期限が切れたセッションをユーザが利用することはできませんが、[`clearsessions`](/ja/4.2/ref/django-admin/#django-admin-clearsessions) 管理コマンドを実行するまでは、ふつうはデータベースに保存されています。

#### `classmethod get_session_store_class()`

セッションモデルで使用するセッションストアクラスを返します。

#### `get_decoded()`

デコードしたセッションデータを返します。

デコードは、セッションストアのクラスで実行されます。

[`BaseSessionManager`](#django.contrib.sessions.base_session.BaseSessionManager) のサブクラスを作ることで、モデルマネージャをカスタマイズすることもできます。

#### `class base_session.BaseSessionManager`

#### `encode(session_dict)`

与えられたセッションディクショナリを、シリアライズ・エンコードした文字列として返します。

エンコードは、モデルクラスに関連付けられたセッションストアのクラスで実行されます。

#### `save(session_key, session_dict, expire_date)`

与えられたセッションキーに対するセッションデータを保存します。データが空の場合には、セッションを削除します。

`SessionStore` クラスのカスタマイズは、以下に挙げるメソッドやプロパティをオーバーライドすることで行えます。

#### `class backends.db.SessionStore`

データベースを使ったセッションストアを実装しています。

#### `classmethod get_model_class()`

カスタマイズしたセッションモデルを返す必要がある場合には、このメソッドをオーバーライドします。

#### `create_model_instance(data)`

現在のセッションの状態を表す、セッションモデルオブジェクトの新しいインスタンスを返します。

このメソッドをオーバーライドすると、セッションモデルのデータをデータベースへ保存する前に修正することができます。

#### `class backends.cached_db.SessionStore`

キャッシュデータベースを使ったセッションストアを実装しています。

#### `cache_key_prefix`

キャッシュのキー文字列を作るためにセッションキーに追加するプリフィックスです。

### カスタマイズ例

The example below shows a custom database-backed session engine that includes
an additional database column to store an account ID (thus providing an option
to query the database for all active sessions for an account):

```
from django.contrib.sessions.backends.db import SessionStore as DBStore
from django.contrib.sessions.base_session import AbstractBaseSession
from django.db import models

class CustomSession(AbstractBaseSession):
    account_id = models.IntegerField(null=True, db_index=True)

    @classmethod
    def get_session_store_class(cls):
        return SessionStore

class SessionStore(DBStore):
    @classmethod
    def get_model_class(cls):
        return CustomSession

    def create_model_instance(self, data):
        obj = super().create_model_instance(data)
        try:
            account_id = int(data.get("_auth_user_id"))
        except (ValueError, TypeError):
            account_id = None
        obj.account_id = account_id
        return obj
```

If you are migrating from the Django's built-in `cached_db` session store to
a custom one based on `cached_db`, you should override the cache key prefix
in order to prevent a namespace clash:

```
class SessionStore(CachedDBStore):
    cache_key_prefix = "mysessions.custom_cached_db_backend"

    # ...
```

## Session IDs in URLs

The Django sessions framework is entirely, and solely, cookie-based. It does
not fall back to putting session IDs in URLs as a last resort, as PHP does.
This is an intentional design decision. Not only does that behavior make URLs
ugly, it makes your site vulnerable to session-ID theft via the "Referer"
header.
