メッセージフレームワークLink to this heading
Web アプリケーションでは非常に一般的に、フォームやその他のユーザーインプットのプロセスの後、ユーザーに向けて一過性の通知メッセージ ("フラッシュメッセージ" とも言われます) を表示する必要があります。
Django は、anonymous および認証済みユーザーの両方に対して、Cookie とセッションをベースにしたメッセージングを完全にサポートしています。このメッセージフレームワークは、一時的に一つのリクエスト内にメッセージを保管し、その後のリクエスト (通常、直後のリクエスト) 内で表示するために、これらを検索することを可能にします。全てのメッセージは、優先順位 (例えば info、 warning、ないし 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 backend は sessions に依存します。そのため
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 パスに設定することで他のストレージクラスを選べます。例えば:
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 から直接インポートできるビルトインのレベルは以下の通りです:
定数 |
目的 |
|---|---|
|
プロダクション環境では無視 (ないし削除) される、開発に関連したメッセージ |
|
ユーザーに何か情報を伝えるメッセージ |
|
あるアクションが成功した、例えば "あなたのプロフィールは無事に更新されました" |
|
問題は起きなかったが、問題になり得る |
|
あるアクションが成功 しなかった か、他の問題が発生した |
MESSAGE_LEVEL 設定は、最小限の記録されたレベルを変更するため (もしくは リクエストごとに変更 するため)に使うことができます。これ以下のレベルのメッセージを追加しようとしても無視されます。
ビューとテンプレートでメッセージを使うLink to this heading
- add_message(request, level, message, extra_tags='', fail_silently=False)Link to this definition
メッセージを付与するLink to this heading
メッセージを付与するには、以下を呼び出してください:
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.")
メッセージを表示するLink to this heading
- get_messages(request)Link to this definition
In your template, use something like:
{% 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:
{% 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 の中に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
Messageclass. They have only a few attributes:message: メッセージの実際のテキストです。level: メッセージのタイプを説明する数値です (詳細は上述の message levels セクション)。tags: スペースによって区切られた、全てのメッセージのタグを結合する文字列 (extra_tagsとlevel_tag) です。extra_tags: スペースによって区切られた、メッセージのカスタムタグを含む文字列です。空がデフォルトです。level_tag: レベルを表す文字列です。デフォルトでは定数名の小文字バージョンですが、MESSAGE_TAGS設定によって変更することができます。
独自のメッセージレベルを作成するLink to this heading
メッセージレベルは実際には単なる整数なので、独自のレベル定数を定義して、よりカスタマイズされたユーザーフィードバックを作成することができます。例えば:
CRITICAL = 50
def my_view(request):
messages.add_message(request, CRITICAL, "A serious error occurred.")
独自のメッセージレベルを作成するときには、既存のレベルを上書きしないように気をつけてください。ビルトインのレベルで使われている値は以下の通りです:
レベル定数 |
値 |
|---|---|
|
10 |
|
20 |
|
25 |
|
30 |
|
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:
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:
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.
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:
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
FormViewbased classes- get_success_message(cleaned_data)Link to this definition
cleaned_datais the cleaned data from the form which is used for string formatting
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"
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:
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:
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: