# Django 5.2.9 ドキュメント

# メッセージフレームワーク

Web アプリケーションでは非常に一般的に、フォームやその他のユーザーインプットのプロセスの後、ユーザーに向けて一過性の通知メッセージ ("フラッシュメッセージ" とも言われます) を表示する必要があります。

Django は、anonymous および認証済みユーザーの両方に対して、Cookie とセッションをベースにしたメッセージングを完全にサポートしています。このメッセージフレームワークは、一時的に一つのリクエスト内にメッセージを保管し、その後のリクエスト (通常、直後のリクエスト) 内で表示するために、これらを検索することを可能にします。全てのメッセージは、優先順位 (たとえば `info`、`warning`、`error`) を決定づける特定の `level` でタグづけされます。

## メッセージを有効にする

メッセージは、 ミドルウェア クラスと、それに対応する コンテキストプロセッサー を通して実行されます。

`django-admin startproject` によって生成されたデフォルトの `settings.py` は、メッセージ機能を有効にするために必要な設定を全て含んでいます:

- `'django.contrib.messages'` は、`INSTALLED_APPS` の中にあります。

- `MIDDLEWARE` は `'django.contrib.sessions.middleware.SessionMiddleware'` と `'django.contrib.messages.middleware.MessageMiddleware'` を含みます。

  デフォルトの ストレージバックエンド は sessions に依存します。そのため `SessionMiddleware` を有効にして、 `MIDDLEWARE` 内で `MessageMiddleware` より前に記述する必要があります。

- `TEMPLATES` 設定で定義した `DjangoTemplates` バックエンドの `'context_processors'` オプションは、`'django.contrib.messages.context_processors.messages'` を含みます。

メッセージを使いたくない場合は、`INSTALLED_APPS` から `'django.contrib.messages'` を、`MIDDLEWARE` から `MessageMiddleware` 行を、そして `TEMPLATES` から `messages` コンテキストプロセッサーを削除できます。

## メッセージエンジンを設定する

### ストレージバックエンド

メッセージフレームワークは、一時的なメッセージを保管するために、異なるバックエンドを使うことができます。

Django は、`django.contrib.messages` の中で、以下の3つのビルトインのストレージクラスを提供しています:

class storage.session.SessionStorage

  このクラスは、すべてのメッセージをリクエストのセッション内部に保管します。ゆえに、Django の `contrib.sessions` アプリケーションが必要となります。

class storage.cookie.CookieStorage

  このクラスは、複数のリクエストにわたって通知を保持するために、Cookie (改ざんを防ぐため秘密のハッシュで署名されます) にメッセージデータを保管します。古いメッセージは Cookie データのサイズが 2048 バイトを超えると破棄されます。

class storage.fallback.FallbackStorage

  このクラスは、まず `CookieStorage` を使い、単一の Cookie に合わないメッセージに対して `SessionStorage` を使います。Django の `contrib.sessions` アプリケーションも必要となります。

  この動作は、可能な限りセッションへの書き込みを避けます。一般的なケースでは最高のパフォーマンスを提供するはずです。

`FallbackStorage` はデフォルトのストレージクラスです。もしあなたのニーズに合わないときは、`MESSAGE_STORAGE` を完全な import パスに設定することで他のストレージクラスを選べます。次に例を示します。

    MESSAGE_STORAGE = "django.contrib.messages.storage.cookie.CookieStorage"

class storage.base.BaseStorage

独自のストレージクラスに書き込むためには、 `django.contrib.messages.storage.base` 内の `BaseStorage` クラスをサブクラス化して、 `_get` と `_store` メソッドを実装してください。

### メッセージレベル

メッセージフレームワークは、Python ロギングモジュールに似た、設定可能なレベルアーキテクチャに基づきます。メッセージレベルは、タイプによるグループメッセージを可能にします。これにより、ビューやテンプレートの中で異なるフィルタおよび表示ができるようになります。

`django.contrib.messages` から直接インポートできるビルトインのレベルは以下の通りです:

定数 | 目的
--- | ---
`DEBUG` | プロダクション環境では無視 (ないし削除) される、開発に関連したメッセージ
`INFO` | ユーザーに何か情報を伝えるメッセージ
`SUCCESS` | あるアクションが成功した、例えば "あなたのプロフィールは無事に更新されました"
`WARNING` | 問題は起きなかったが、問題になり得る
`ERROR` | あるアクションが成功 しなかった か、他の問題が発生した

`MESSAGE_LEVEL` 設定は、最小限の記録されたレベルを変更するため (もしくは リクエストごとに変更 するため)に使うことができます。これ以下のレベルのメッセージを追加しようとしても無視されます。

### メッセージタグ

メッセージタグは、メッセージレベルの表現文字列に加えて、ビューの中で直接付与される追加のタグです (詳しくは、以下の 追加のメッセージタグを付与する を参照してください )。タグは文字列で保管され、スペースによって区切られます。典型的には、メッセージタグは、メッセージタイプに基いてメッセージのスタイルをカスタマイズするために、CSS のクラスとして利用されます。デフォルトでは、それぞれのレベルは、レベル定数を小文字にした、単一のタグを持っています。

レベル定数 | タグ
--- | ---
`DEBUG` | `debug`
`INFO` | `info`
`SUCCESS` | `success`
`WARNING` | `warning`
`ERROR` | `error`

メッセージレベル (ビルトインないしカスタムのいずれか) のデフォルトのタグを変更するためには、 `MESSAGE_TAGS` 設定を、あなたが変更したいと思うレベルを含むディクショナリにセットしてください。これでデフォルトのタグを拡張するので、あなたがすべきことはオーバーライドしようとするレベルに対してタグを提供することだけです:

    from django.contrib.messages import constants as messages

    MESSAGE_TAGS = {
        messages.INFO: "",
        50: "critical",
    }

## ビューとテンプレートでメッセージを使う

add_message(request, level, message, extra_tags='', fail_silently=False)

### メッセージを付与する

メッセージを付与するには、以下を呼び出してください:

    from django.contrib import messages

    messages.add_message(request, messages.INFO, "Hello world.")

いくつかのショートカットメソッドは、一般的に使われるタグ (通常、メッセージのHTMLクラスとして表されます) とともにメッセージを付与する標準的な方法を提供します:

    messages.debug(request, "%s SQL statements were executed." % count)
    messages.info(request, "Three credits remain in your account.")
    messages.success(request, "Profile details updated.")
    messages.warning(request, "Your account expires in three days.")
    messages.error(request, "Document deleted.")

### メッセージを表示する

get_messages(request)

テンプレート では、次のようなものを使ってください:

    {% if messages %}
    <ul class="messages">
        {% for message in messages %}
        <li{% if message.tags %} class="{{ message.tags }}"{% endif %}>{{ message }}</li>
        {% endfor %}
    </ul>
    {% endif %}

コンテキストプロセッサーを使っている場合、テンプレートは `RequestContext` でレンダリングされる必要があります。もしくは、 `messages` をテンプレートコンテキストに対して有効にしてください。

メッセージが一つしかないとわかっている場合でも、 `messages` 配列をイテレートする必要があります。そうしないとメッセージストレージは次のリクエストのためにクリアされないからです。

コンテキストプロセッサーは、メッセージレベルの名前と数値を対応付ける `DEFAULT_MESSAGE_LEVELS` 変数も提供します:

    {% if messages %}
    <ul class="messages">
        {% for message in messages %}
        <li{% if message.tags %} class="{{ message.tags }}"{% endif %}>
            {% if message.level == DEFAULT_MESSAGE_LEVELS.ERROR %}Important: {% endif %}
            {{ message }}
        </li>
        {% endfor %}
    </ul>
    {% endif %}

テンプレート以外では、 `get_messages()` を使うことができます:

    from django.contrib.messages import get_messages

    storage = get_messages(request)
    for message in storage:
        do_something_with_the_message(message)

たとえば、すべてのメッセージを取得して、`TemplateResponseMixin` の代わりに JSONResponseMixin で返すことができます。

`get_messages()` は設定されたストレージバックエンドのインスタンスを返します。

### `Message` クラス

class Message

  テンプレート内のメッセージのリストをループさせると、 `Message` クラスのインスタンスが得られます。これらのインスタンスにはいくつかの属性しかありません:

  - `message`: メッセージの実際のテキストです。

  - `level`: メッセージのタイプを説明する数値です (詳細は上述の message levels セクション)。

  - `tags`: スペースによって区切られた、全てのメッセージのタグを結合する文字列 (`extra_tags` と `level_tag`) です。

  - `extra_tags`: スペースによって区切られた、メッセージのカスタムタグを含む文字列です。空がデフォルトです。

  - `level_tag`: レベルを表す文字列です。デフォルトでは定数名の小文字バージョンですが、`MESSAGE_TAGS` 設定によって変更できます。

### 独自のメッセージレベルを作成する

メッセージレベルは実際には単なる整数なので、独自のレベル定数を定義して、よりカスタマイズされたユーザーフィードバックを作成できます。次に例を示します。

    CRITICAL = 50

    def my_view(request):
        messages.add_message(request, CRITICAL, "A serious error occurred.")

独自のメッセージレベルを作成するときには、既存のレベルを上書きしないように気をつけてください。ビルトインのレベルで使われている値は以下の通りです:

レベル定数 | 値
--- | ---
`DEBUG` | 10
`INFO` | 20
`SUCCESS` | 25
`WARNING` | 30
`ERROR` | 40

HTML や CSS の中で独自のレベルを指定する必要がある場合は、`MESSAGE_TAGS` 設定を通してマップを提供する必要があります。

注釈

再利用可能なアプリケーションを作成している場合には、ビルトインの message levels だけを使い、独自のレベルに依存しないことが推奨されます。

### リクエストごとの最小記録レベルを変更する

最小記録レベルは、`set_level` メソッドを使用してリクエストごとに設定できます。

    from django.contrib import messages

    # Change the messages level to ensure the debug message is added.
    messages.set_level(request, messages.DEBUG)
    messages.debug(request, "Test message...")

    # In another request, record only messages with a level of WARNING and higher
    messages.set_level(request, messages.WARNING)
    messages.success(request, "Your profile was updated.")  # ignored
    messages.warning(request, "Your account is about to expire.")  # recorded

    # Set the messages level back to default.
    messages.set_level(request, None)

同様に、現在の有効レベルは `get_level` を使って取得できます。

    from django.contrib import messages

    current_level = messages.get_level(request)

最小記録レベルが機能する仕組みについての詳細は、上記の Message levels を参照してください。

### 追加のメッセージタグを追加する

メッセージタグをより直接的に制御したい場合は、追加メソッドのいずれかに、追加のタグを含む文字列を任意で指定できます:

    messages.add_message(request, messages.INFO, "Over 9000!", extra_tags="dragonball")
    messages.error(request, "Email box full", extra_tags="email")

追加タグは、そのレベルのデフォルトタグの前に追加され、スペースで区切られます。

### メッセージフレームワークが無効になっているときのエラーを隠す

再利用可能なアプリ (または他のコード) を書いており、メッセージング機能を含めたいが、利用者に無理に有効化させたくない場合は、任意の `add_message` ファミリーのメソッドに `fail_silently=True` という追加のキーワード引数を渡すことができます。たとえば:

    messages.add_message(
        request,
        messages.SUCCESS,
        "Profile details updated.",
        fail_silently=True,
    )
    messages.info(request, "Hello world.", fail_silently=True)

注釈

`fail_silently=True` を設定すると、メッセージフレームワークが無効になっており、`add_message` メソッドのいずれかを使用しようとした際に発生するはずの `MessageFailure` を隠します。それ以外の理由で発生する失敗は隠されません。

### クラスベースのビューにメッセージを追加する

class views.SuccessMessageMixin

  `FormView` をベースにしたクラスに、成功メッセージ属性を追加します。

  get_success_message(cleaned_data)

    `cleaned_data` はフォームからのクリーンなデータであり、文字列フォーマットに使用されます。

Example views.py:

    from django.contrib.messages.views import SuccessMessageMixin
    from django.views.generic.edit import CreateView
    from myapp.models import Author

    class AuthorCreateView(SuccessMessageMixin, CreateView):
        model = Author
        success_url = "/success/"
        success_message = "%(name)s was created successfully"

`form` からのクリーン済みデータは、 `%(field_name)s` 構文を使用して文字列補完に利用できます。ModelForms の場合、保存された `object` からフィールドにアクセスが必要な場合は、 `get_success_message()` メソッドをオーバーライドしてください。

ModelForms 用の views.py の例:

    from django.contrib.messages.views import SuccessMessageMixin
    from django.views.generic.edit import CreateView
    from myapp.models import ComplicatedModel

    class ComplicatedCreateView(SuccessMessageMixin, CreateView):
        model = ComplicatedModel
        success_url = "/success/"
        success_message = "%(calculated_field)s was created successfully"

        def get_success_message(self, cleaned_data):
            return self.success_message % dict(
                cleaned_data,
                calculated_field=self.object.calculated_field,
            )

## メッセージの有効期限

メッセージは、ストレージインスタンスがイテレートされる際にクリアされるようにマークされています (そして、応答が処理される際にもクリアされます)。

メッセージがクリアされるのを避けるために、イテレートの後にメッセージストレージを `False` に設定できます:

    storage = messages.get_messages(request)
    for message in storage:
        do_something_with(message)
    storage.used = False

## 並列リクエストの動作

クッキー (そしてセッション) の仕組みから、同じクライアントが複数の要求を並行して行い、メッセージを設定または取得する場合、クッキーやセッションを使用するバックエンドの動作は定義されていません。たとえば、クライアントが1つのウィンドウ (またはタブ) でメッセージを作成する要求を開始し、別のウィンドウで未読メッセージを取得する要求を開始するとき、最初のウィンドウがリダイレクトされる前に、そのメッセージが最初ではなく、代わりに2番目のウィンドウに表示されることがあります。

要するに、同じクライアントからの複数の同時リクエストが関わると、メッセージがそれらを作成した同じウィンドウに必ず届くわけではなく、場合によっては全く届かないことがあります。ほとんどのアプリケーションでは通常問題とならず、HTML5では各ウィンドウ/タブが独自の閲覧コンテキストを持つため、これは問題にならなくなります。

## 設定

いくつかの 設定 を使用して、メッセージの動作を制御できます。

- `MESSAGE_LEVEL`

- `MESSAGE_STORAGE`

- `MESSAGE_TAGS`

Cookiesを使用するバックエンドでは、Cookieの設定はセッションCookieの設定から取得されます。

- `SESSION_COOKIE_DOMAIN`

- `SESSION_COOKIE_SECURE`

- `SESSION_COOKIE_HTTPONLY`

## テスト

このモジュールは、`HttpResponse` に添付されたメッセージをテストするためのカスタマイズされたテストアサーションメソッドを提供しています。

このアサーションを利用するには、クラス階層に `MessagesTestMixin` を追加してください。

    from django.contrib.messages.test import MessagesTestMixin
    from django.test import TestCase

    class MsgTestCase(MessagesTestMixin, TestCase):
        pass

次に、テストで `MsgTestCase` を継承してください。

MessagesTestMixin.assertMessages(response, expected_messages, ordered=True)

  `response` に追加された `messages` が `expected_messages` と一致することをアサートします。

  `expected_messages` は `Message` オブジェクトのリストです。

  デフォルトでは、比較は順序に依存します。これを無効にするには、 `ordered` 引数を `False` に設定します。