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'
を含みます。
デフォルトの 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
コンテクストプロセッサーを削除できます。
メッセージフレームワークは、一時的なメッセージを保管するために、異なるバックエンドを使うことができます。
Django は、django.contrib.messages
の中で、以下の3つのビルトインのストレージクラスを提供しています:
storage.session.
SessionStorage
¶このクラスは、すべてのメッセージをリクエストのセッション内部に保管します。ゆえに、Django の contrib.sessions
アプリケーションが必要となります。
storage.cookie.
CookieStorage
¶このクラスは、複数のリクエストにわたって通知を保持するために、Cookie (改ざんを防ぐため秘密のハッシュで署名されます) にメッセージデータを保管します。古いメッセージは Cookie データのサイズが 2048 バイトを超えると破棄されます。
Messages format was changed to the RFC 6265 compliant format.
storage.fallback.
FallbackStorage
¶このクラスは、まず CookieStorage
を使い、単一の Cookie に合わないメッセージに対して SessionStorage
を使います。Django の contrib.sessions
アプリケーションも必要となります。
この動作は、可能な限りセッションへの書き込みを避けます。一般的なケースでは最高のパフォーマンスを提供するはずです。
FallbackStorage
はデフォルトのストレージクラスです。もしあなたのニーズに合わないときは、 MESSAGE_STORAGE
を完全な import パスに設定することで他のストレージクラスを選べます。例えば:
MESSAGE_STORAGE = 'django.contrib.messages.storage.cookie.CookieStorage'
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
をテンプレートコンテクストに対して有効にしてください。
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.
コンテクストプロセッサーは、メッセージレベルの名前と数値を対応させた 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 の中にreturnすることができます。
get_messages()
は設定されたストレージバックエンドのインスタンスを返します。
Message
クラス¶storage.base.
Message
¶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_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 だけを使い、独自のレベルに依存しないことが推奨されます。
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.
For more direct control over message tags, you can optionally provide a string containing extra tags to any of the add methods:
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.
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)
注釈
Setting fail_silently=True
only hides the MessageFailure
that would
otherwise occur when the messages framework disabled and one attempts to
use one of the add_message
family of methods. It does not hide failures
that may occur for other reasons.
views.
SuccessMessageMixin
¶Adds a success message attribute to
FormView
based classes
get_success_message
(cleaned_data)¶cleaned_data
is 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,
)
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
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.
2022年6月01日