メッセージフレームワーク¶
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",
}
ビューとテンプレートでメッセージを使う¶
メッセージを付与する¶
メッセージを付与するには、以下を呼び出してください:
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.")
メッセージを表示する¶
テンプレート では、次のようなものを使ってください:
{% 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では各ウィンドウ/タブが独自の閲覧コンテキストを持つため、これは問題にならなくなります。
テスト¶
このモジュールは、HttpResponse
に添付されたメッセージをテストするためのカスタマイズされたテストアサーションメソッドを提供しています。
このアサーションを利用するには、クラス階層に MessagesTestMixin
を追加してください。
from django.contrib.messages.test import MessagesTestMixin
from django.test import TestCase
class MsgTestCase(MessagesTestMixin, TestCase):
pass
次に、テストで MsgTestCase
を継承してください。