メッセージフレームワークLink to this heading

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

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

メッセージを有効にするLink to this heading

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

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

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

  • MIDDLEWARE'django.contrib.sessions.middleware.SessionMiddleware''django.contrib.messages.middleware.MessageMiddleware' を含みます。

    デフォルトの storage backendsessions に依存します。そのため SessionMiddleware を有効にして、 MIDDLEWARE 内で MessageMiddleware より前に記述する必要があります。

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

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

メッセージエンジンを設定するLink to this heading

ストレージバックエンドLink to this heading

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

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

class storage.session.SessionStorageLink to this definition

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

class storage.cookie.CookieStorageLink to this definition

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

class storage.fallback.FallbackStorageLink to this definition

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

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

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

Code
MESSAGE_STORAGE = "django.contrib.messages.storage.cookie.CookieStorage"
class storage.base.BaseStorageLink to this definition

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

メッセージレベルLink to this heading

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

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

定数

目的

DEBUG

プロダクション環境では無視 (ないし削除) される、開発に関連したメッセージ

INFO

ユーザーに何か情報を伝えるメッセージ

SUCCESS

あるアクションが成功した、例えば "あなたのプロフィールは無事に更新されました"

WARNING

問題は起きなかったが、問題になり得る

ERROR

あるアクションが成功 しなかった か、他の問題が発生した

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

メッセージタグLink to this heading

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

レベル定数

タグ

DEBUG

debug

INFO

info

SUCCESS

success

WARNING

warning

ERROR

error

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

Code
from django.contrib.messages import constants as messages

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

ビューとテンプレートでメッセージを使うLink to this heading

add_message(request, level, message, extra_tags='', fail_silently=False)Link to this definition

メッセージを付与するLink to this heading

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

Code
from django.contrib import messages

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

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

Code
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.")

メッセージを表示するLink to this heading

get_messages(request)Link to this definition

In your template, use something like:

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

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

Even if you know there is only one message, you should still iterate over the messages sequence, because otherwise the message storage will not be cleared for the next request.

The context processor also provides a DEFAULT_MESSAGE_LEVELS variable which is a mapping of the message level names to their numeric value:

Django template
{% 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() を使うことができます:

Code
from django.contrib.messages import get_messages

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

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

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

Message クラスLink to this heading

class storage.base.MessageLink to this definition

When you loop over the list of messages in a template, what you get are instances of the Message class. They have only a few attributes:

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

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

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

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

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

独自のメッセージレベルを作成するLink to this heading

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

Code
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 設定を通してマップを提供する必要があります。

Changing the minimum recorded level per-requestLink to this heading

The minimum recorded level can be set per request via the set_level method:

Code
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)

Similarly, the current effective level can be retrieved with get_level:

Code
from django.contrib import messages

current_level = messages.get_level(request)

For more information on how the minimum recorded level functions, see Message levels above.

Adding extra message tagsLink to this heading

For more direct control over message tags, you can optionally provide a string containing extra tags to any of the add methods:

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

Extra tags are added before the default tag for that level and are space separated.

Failing silently when the message framework is disabledLink to this heading

If you're writing a reusable app (or other piece of code) and want to include messaging functionality, but don't want to require your users to enable it if they don't want to, you may pass an additional keyword argument fail_silently=True to any of the add_message family of methods. For example:

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

Adding messages in class-based viewsLink to this heading

class views.SuccessMessageMixinLink to this definition

Adds a success message attribute to FormView based classes

get_success_message(cleaned_data)Link to this definition

cleaned_data is the cleaned data from the form which is used for string formatting

Example views.py:

Code
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"

The cleaned data from the form is available for string interpolation using the %(field_name)s syntax. For ModelForms, if you need access to fields from the saved object override the get_success_message() method.

Example views.py for ModelForms:

Code
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,
        )

Expiration of messagesLink to this heading

The messages are marked to be cleared when the storage instance is iterated (and cleared when the response is processed).

To avoid the messages being cleared, you can set the messages storage to False after iterating:

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

Behavior of parallel requestsLink to this heading

Due to the way cookies (and hence sessions) work, the behavior of any backends that make use of cookies or sessions is undefined when the same client makes multiple requests that set or get messages in parallel. For example, if a client initiates a request that creates a message in one window (or tab) and then another that fetches any uniterated messages in another window, before the first window redirects, the message may appear in the second window instead of the first window where it may be expected.

In short, when multiple simultaneous requests from the same client are involved, messages are not guaranteed to be delivered to the same window that created them nor, in some cases, at all. Note that this is typically not a problem in most applications and will become a non-issue in HTML5, where each window/tab will have its own browsing context.

設定Link to this heading

A few settings give you control over message behavior:

For backends that use cookies, the settings for the cookie are taken from the session cookie settings: