訊息框架¶
在 Web 應用程式中,您通常需要在處理表單或其他類型的使用者輸入後,向使用者顯示一次性的通知訊息(也稱為「快閃訊息」)。
為此,Django 為匿名和已驗證的使用者提供對基於 Cookie 和 Session 的訊息傳遞的完整支援。訊息框架允許您在一個請求中暫時儲存訊息,並在後續請求(通常是下一個請求)中檢索這些訊息以進行顯示。每個訊息都會被標記一個特定的 level
,該 level 決定了其優先順序(例如,info
、warning
或 error
)。
啟用訊息¶
訊息是透過 中介軟體 類別和對應的 上下文處理器 來實現的。
由 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
中提供了三個內建的儲存類別
- class storage.session.SessionStorage¶
此類別將所有訊息儲存在請求的 Session 內。因此,它需要 Django 的
contrib.sessions
應用程式。
- class storage.cookie.CookieStorage¶
此類別將訊息資料儲存在 Cookie 中(以秘密雜湊簽署,以防止篡改),以跨請求持續通知。如果 Cookie 資料大小超過 2048 位元組,則會捨棄舊訊息。
- class storage.fallback.FallbackStorage¶
此類別首先使用
CookieStorage
,然後回退到使用SessionStorage
來儲存無法放入單一 Cookie 中的訊息。它也需要 Django 的contrib.sessions
應用程式。這種行為會盡可能避免寫入 Session。它應該在一般情況下提供最佳效能。
FallbackStorage
是預設的儲存類別。如果它不適合您的需求,您可以透過將 MESSAGE_STORAGE
設定為其完整導入路徑來選擇另一個儲存類別,例如
MESSAGE_STORAGE = "django.contrib.messages.storage.cookie.CookieStorage"
- class storage.base.BaseStorage¶
若要編寫您自己的儲存類別,請子類化 django.contrib.messages.storage.base
中的 BaseStorage
類別,並實作 _get
和 _store
方法。
訊息等級¶
訊息框架基於類似於 Python 日誌模組的可設定等級架構。訊息等級允許您依類型對訊息進行分組,以便它們可以在檢視和範本中進行篩選或以不同的方式顯示。
可以從 django.contrib.messages
直接匯入的內建等級為
常數 |
目的 |
---|---|
|
與開發相關的訊息,這些訊息在生產部署中將被忽略(或移除) |
|
給使用者的資訊性訊息 |
|
動作成功,例如「您的個人資料已成功更新」 |
|
未發生故障,但可能迫在眉睫 |
|
動作未成功,或發生其他故障 |
MESSAGE_LEVEL
設定可用於變更記錄的最低等級(或者可以依請求變更)。嘗試加入等級低於此等級的訊息將被忽略。
在檢視和範本中使用訊息¶
加入訊息¶
若要加入訊息,請呼叫
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)
例如,您可以獲取所有訊息,並將它們以 JSONResponseMixin 的形式返回,而不是以 TemplateResponseMixin
的形式返回。
get_messages()
將會返回已設定的儲存後端的實例。
Message
類別¶
- class Message[原始碼]¶
當您在模板中迴圈處理訊息列表時,您所獲得的是
Message
類別的實例。它們只有少數幾個屬性message
:訊息的實際文字內容。level
:描述訊息類型的整數(請參閱上方訊息層級章節)。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.")
在建立自訂訊息層級時,您應謹慎避免覆寫現有的層級。內建層級的值為:
等級常數 |
值 |
---|---|
|
10 |
|
20 |
|
25 |
|
30 |
|
40 |
如果您需要在 HTML 或 CSS 中識別自訂層級,您需要透過 MESSAGE_TAGS
設定來提供對應。
注意
如果您正在建立可重複使用的應用程式,建議僅使用內建的訊息層級,而不要依賴任何自訂層級。
變更每個請求的最小記錄層級¶
可以使用 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)
如需有關最小記錄層級如何運作的詳細資訊,請參閱上方的訊息層級。
當訊息框架停用時靜默失敗¶
如果您正在撰寫可重複使用的應用程式(或其他程式碼),並且想要包含訊息功能,但不希望要求使用者在他們不需要時啟用此功能,您可以將額外的關鍵字引數 fail_silently=True
傳遞給任何 add_message
系列的方法。例如
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
是表單中已清除的資料,用於字串格式化
範例 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"
可以使用 %(field_name)s
語法來對 form
中已清除的資料進行字串插值。對於 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
平行請求的行為¶
由於 Cookie(以及 Session)的運作方式,當同一用戶端發出多個平行請求以設定或取得訊息時,任何使用 Cookie 或 Session 的後端的行為都是未定義的。例如,如果一個用戶端在一個視窗(或標籤)中發起一個建立訊息的請求,然後在另一個視窗中發起另一個提取任何未迭代訊息的請求,在第一個視窗重新導向之前,訊息可能會出現在第二個視窗中,而不是預期的第一個視窗中。
簡而言之,當涉及來自同一用戶端的多個同時請求時,無法保證訊息會傳遞到建立它們的同一個視窗,或者在某些情況下根本不會傳遞。請注意,這在大多數應用程式中通常不是問題,並且在 HTML5 中將不再是問題,因為每個視窗/標籤都有自己的瀏覽上下文。
設定¶
一些設定可讓您控制訊息行為
對於使用 Cookie 的後端,Cookie 的設定取自 Session Cookie 設定
測試¶
此模組提供客製化的測試斷言方法,用於測試附加到 HttpResponse
的訊息。
若要使用此斷言,請將 MessagesTestMixin
新增至類別階層
from django.contrib.messages.test import MessagesTestMixin
from django.test import TestCase
class MsgTestCase(MessagesTestMixin, TestCase):
pass
然後,在您的測試中繼承自 MsgTestCase
。