Ramverket för meddelanden¶
I webbapplikationer är det vanligt att du behöver visa ett engångsmeddelande (även kallat ”flashmeddelande”) till användaren efter att ha bearbetat ett formulär eller någon annan typ av användarinmatning.
För detta ger Django fullt stöd för cookie- och sessionsbaserad meddelandehantering, för både anonyma och autentiserade användare. Med meddelanderamen kan du tillfälligt lagra meddelanden i en begäran och hämta dem för visning i en efterföljande begäran (vanligtvis nästa). Varje meddelande är taggat med en specifik ”nivå” som bestämmer dess prioritet (t.ex. ”info”, ”varning” eller ”fel”).
Aktivering av meddelanden¶
Meddelanden implementeras genom en middleware-klass och motsvarande context processor.
Standardinställningen settings.py
som skapats av django-admin startproject
innehåller redan alla inställningar som krävs för att aktivera meddelandefunktionen:
'django.contrib.messages'
finns iINSTALLED_APPS
.MIDDLEWARE
innehåller'django.contrib.sessions.middleware.SessionMiddleware'
och'django.contrib.messages.middleware.MessageMiddleware'
.Standard storage backend förlitar sig på sessions. Det är därför
SessionMiddleware
måste vara aktiverat och visas föreMessageMiddleware
iMIDDLEWARE
.Alternativet
'context_processors'
för backendDjangoTemplates
som definieras i dinTEMPLATES
-inställning innehåller'django.contrib.messages.context_processors.messages'
.
Om du inte vill använda meddelanden kan du ta bort 'django.contrib.messages'
från din INSTALLED_APPS
, raden MessageMiddleware
från MIDDLEWARE
och kontextprocessorn messages
från TEMPLATES
.
Konfigurera meddelandemotorn¶
Backend för lagring¶
Meddelanderamen kan använda olika backends för att lagra tillfälliga meddelanden.
Django tillhandahåller tre inbyggda lagringsklasser i django.contrib.messages
:
- class storage.session.SessionStorage¶
Den här klassen lagrar alla meddelanden i begäran om session. Därför kräver den Djangos
contrib.sessions
applikation.
- class storage.cookie.CookieStorage¶
Denna klass lagrar meddelandedata i en cookie (signerad med en hemlig hash för att förhindra manipulation) för att hålla kvar meddelanden över förfrågningar. Gamla meddelanden tas bort om cookiedatastorleken skulle överstiga 2048 byte.
- class storage.fallback.FallbackStorage¶
Denna klass använder först
CookieStorage
, och faller tillbaka till att användaSessionStorage
för de meddelanden som inte kunde rymmas i en enda cookie. Den kräver också Djangos applikationcontrib.sessions
.Detta beteende undviker att skriva till sessionen när det är möjligt. Det bör ge bäst prestanda i det allmänna fallet.
FallbackStorage
är standardlagringsklassen. Om den inte är lämplig för dina behov kan du välja en annan lagringsklass genom att ange MESSAGE_STORAGE
till dess fullständiga importsökväg, till exempel:
MESSAGE_STORAGE = "django.contrib.messages.storage.cookie.CookieStorage"
- class storage.base.BaseStorage¶
För att skriva din egen lagringsklass, subklassa klassen BaseStorage
i django.contrib.messages.storage.base
och implementera metoderna _get
och _store
.
Meddelandenivåer¶
Meddelanderamen bygger på en konfigurerbar nivåarkitektur som liknar den i Pythons loggmodul. Med meddelandenivåer kan du gruppera meddelanden efter typ så att de kan filtreras eller visas på olika sätt i vyer och mallar.
De inbyggda nivåerna, som kan importeras direkt från django.contrib.messages
, är:
Konstant |
Syfte |
---|---|
|
Utvecklingsrelaterade meddelanden som kommer att ignoreras (eller tas bort) i en produktionsdistribution |
|
Informationsmeddelanden för användaren |
|
En åtgärd lyckades, t.ex. ”Din profil uppdaterades framgångsrikt” |
”VARNING |
Ett fel inträffade inte men kan vara nära förestående |
|
En åtgärd lyckades inte eller något annat fel inträffade |
Inställningen MESSAGE_LEVEL
kan användas för att ändra den lägsta inspelade nivån (eller så kan den ändras på begäran). Försök att lägga till meddelanden på en lägre nivå än denna ignoreras.
Använda meddelanden i vyer och mallar¶
Lägga till ett meddelande¶
För att lägga till ett meddelande, ring:
from django.contrib import messages
messages.add_message(request, messages.INFO, "Hello world.")
Vissa genvägsmetoder ger ett standardiserat sätt att lägga till meddelanden med vanligt förekommande taggar (som vanligtvis representeras som HTML-klasser för meddelandet):
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.")
Visning av meddelanden¶
I din mall, använd något liknande:
{% if messages %}
<ul class="messages">
{% for message in messages %}
<li{% if message.tags %} class="{{ message.tags }}"{% endif %}>{{ message }}</li>
{% endfor %}
</ul>
{% endif %}
Om du använder kontextprocessorn bör din mall återges med en RequestContext
. Annars ska du se till att messages
är tillgängligt för mallkontexten.
Även om du vet att det bara finns ett meddelande bör du ändå iterera över sekvensen messages
, eftersom meddelandelagret annars inte kommer att rensas för nästa begäran.
Kontextprocessorn tillhandahåller också variabeln DEFAULT_MESSAGE_LEVELS
som är en mappning av meddelandenivåernas namn till deras numeriska värde:
{% 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 %}
Utanför mallar kan du använda get_messages()
:
from django.contrib.messages import get_messages
storage = get_messages(request)
for message in storage:
do_something_with_the_message(message)
Du kan till exempel hämta alla meddelanden för att returnera dem i en JSONResponseMixin istället för en TemplateResponseMixin
.
get_messages()
kommer att returnera en instans av den konfigurerade lagringsbackend.
Klassen Message
(meddelande)¶
- class Message[source]¶
När man loopar över listan med meddelanden i en mall får man fram instanser av klassen
Message
. De har bara ett fåtal attribut:meddelande
: Den faktiska texten i meddelandet.nivå
: Ett heltal som beskriver typen av meddelande (se avsnittet meddelandenivåer ovan).tags
: En sträng som kombinerar alla meddelandets taggar (extra_tags
ochlevel_tag
) separerade med mellanslag.extra_tags
: En sträng som innehåller anpassade taggar för detta meddelande, separerade med mellanslag. Den är tom som standard.level_tag
: Strängrepresentationen av nivån. Som standard är det den gemena versionen av namnet på den associerade konstanten, men detta kan ändras om du behöver genom att använda inställningenMESSAGE_TAGS
.
Skapa anpassade meddelandenivåer¶
Meddelandenivåerna är inget annat än heltal, så du kan definiera dina egna nivåkonstanter och använda dem för att skapa mer anpassad användaråterkoppling, t.ex:
CRITICAL = 50
def my_view(request):
messages.add_message(request, CRITICAL, "A serious error occurred.")
När du skapar egna meddelandenivåer bör du vara försiktig så att du inte överbelastar befintliga nivåer. Värdena för de inbyggda nivåerna är:
Nivå Konstant |
Värde |
---|---|
|
10 |
|
20 |
|
25 |
”VARNING |
30 |
|
40 |
Om du behöver identifiera de anpassade nivåerna i din HTML eller CSS måste du tillhandahålla en mappning via inställningen MESSAGE_TAGS
.
Observera
Om du skapar en återanvändbar applikation rekommenderas att du endast använder de inbyggda message levels och inte förlitar dig på några anpassade nivåer.
Ändring av lägsta inspelade nivå per förfrågan¶
Den lägsta registrerade nivån kan ställas in per begäran via metoden 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)
På samma sätt kan den aktuella effektiva nivån hämtas med get_level
:
from django.contrib import messages
current_level = messages.get_level(request)
För mer information om hur den lägsta inspelningsnivån fungerar, se Meddelandenivåer ovan.
Misslyckas i tysthet när meddelanderamen är inaktiverad¶
Om du skriver en återanvändbar app (eller annan kod) och vill inkludera meddelandefunktionalitet, men inte vill kräva att dina användare aktiverar det om de inte vill, kan du skicka ett ytterligare nyckelordsargument fail_silently=True
till någon av metoderna i add_message
-familjen. Till exempel:
messages.add_message(
request,
messages.SUCCESS,
"Profile details updated.",
fail_silently=True,
)
messages.info(request, "Hello world.", fail_silently=True)
Observera
Om du ställer in fail_silently=True
döljs bara MessageFailure
som annars skulle inträffa när meddelanderamen inaktiveras och man försöker använda en av metoderna i add_message
-familjen. Den döljer inte fel som kan uppstå av andra skäl.
Lägga till meddelanden i klassbaserade vyer¶
- class views.SuccessMessageMixin¶
Lägger till ett attribut för framgångsmeddelande till
FormView
-baserade klasser- get_success_message(cleaned_data)¶
cleaned_data
är de rensade data från formuläret som används för strängformatering
Exempel på 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"
De rensade uppgifterna från formuläret
är tillgängliga för stränginterpolering med syntaxen %(field_name)s
. För ModelForms, om du behöver tillgång till fält från det sparade objektet
åsidosätt metoden get_success_message()
.
Exempel på views.py för 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,
)
Utgång av meddelanden¶
Meddelandena markeras för att rensas när lagringsinstansen itereras (och rensas när svaret bearbetas).
För att undvika att meddelandena rensas kan du ställa in meddelandelagringen till False
efter iteration:
storage = messages.get_messages(request)
for message in storage:
do_something_with(message)
storage.used = False
Beteende för parallella förfrågningar¶
På grund av hur cookies (och därmed sessioner) fungerar, är beteendet hos alla backends som använder cookies eller sessioner odefinierat när samma klient gör flera begäranden som ställer in eller hämtar meddelanden parallellt. Om en klient t.ex. initierar en begäran som skapar ett meddelande i ett fönster (eller en flik) och sedan en annan som hämtar alla oitererade meddelanden i ett annat fönster, innan det första fönstret omdirigeras, kan meddelandet visas i det andra fönstret i stället för i det första fönstret där det kan förväntas.
Kort sagt, när flera samtidiga förfrågningar från samma klient är inblandade, är det inte garanterat att meddelanden levereras till samma fönster som skapade dem eller, i vissa fall, inte alls. Observera att detta normalt inte är ett problem i de flesta tillämpningar och att det kommer att bli ett icke-problem i HTML5, där varje fönster/flik kommer att ha sin egen webbläsarkontext.
Inställningar¶
Några inställningar ger dig kontroll över meddelandets beteende:
För backends som använder cookies hämtas inställningarna för cookien från inställningarna för sessionscookien:
Testar¶
Denna modul erbjuder en skräddarsydd testmetod för att testa meddelanden som är kopplade till en HttpResponse
.
För att dra nytta av denna försäkran, lägg till MessagesTestMixin
i klasshierarkin:
from django.contrib.messages.test import MessagesTestMixin
from django.test import TestCase
class MsgTestCase(MessagesTestMixin, TestCase):
pass
Ärv sedan från MsgTestCase
i dina tester.
- MessagesTestMixin.assertMessages(response, expected_messages, ordered=True)[source]¶
Säkerställer att
messages
som lagts till iresponse
matcharexpected_messages
.expected_messages
är en lista medMessage
-objekt.Som standard är jämförelsen beroende av ordningsföljd. Du kan inaktivera detta genom att ställa in argumentet
ordered
tillFalse
.