Access Messages
This module keeps the same interface of the vanilla Django’s messages framework, and can be used just like shown in the Django docs at https://docs.djangoproject.com/en/3.1/ref/contrib/messages/.
Create a new message
Creating a new message is as straight forward as this:
from django.contrib import messages
messages.info(request, 'Hello world!')
In this example, an information message is created for that request
object.
Warning
In case the request has no user or session provided, the message will be stored in memory for temporary storage available through that request processing. Messages added that are not used until the response will not be available anymore.
Extra tags can be attached to the message, as a string or list of strings. For example:
from django.contrib import messages
messages.info(request, 'Hello world!', extra_tags="debug")
messages.info(request, 'Hello world!', extra_tags=["debug", "test"])
Those extra tags will be save with the message and can be used for filtering, rendering or any other use you can think of.
About the levels
The django’s messages framework uses configurable level architecture similar to that of the Python logging module. Each message provide a integer level that is represented by a tag, and can be used to group messages by type, filtered or to be rendered differently.
This module keeps the same architecture.
The django’s messages framework provides a default of 5 levels.
This can be configured using the MESSAGE_TAGS
setting.
For example:
MESSAGE_TAGS = {
10: 'debug',
20: 'info',
25: 'success',
30: 'warning',
40: 'error',
50: 'critical',
}
Note
MessageSerializer
and alter the Rest API schema.When doing so, you will need to manually create a new message (the default shortcuts will not suit you). It is advised to store any custom level in a constant variable for a more readable code. For example:
from django.contrib import messages
CRITICAL = 50
messages.add_message(request, CRITICAL, 'Hello world!')
Using those message levels, you can set a minimum level, so that any message with a lower level will be ignored and will not be saved.
Configuring minimum level can be done at the project level via the MESSAGE_LEVEL
setting.
For example:
MESSAGE_LEVEL = 20
# (this is the actual default value)
Alternatively, it can be configured per request:
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)
See also
From the django docs https://docs.djangoproject.com/en/3.1/ref/contrib/messages/#changing-the-minimum-recorded-level-per-request
Reading messages
Sometimes it is useful to access and read the messages directly in your code.
Accessing the messages can be performed exactly with the same interface as the default Django messages framework, but with some extra flairs.
The vanilla ways to access the messages is inside templates:
{% 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 %}
Another classic way is iterating over the messages storage:
from django.contrib.messages import get_messages
storage = get_messages(request)
for message in storage:
print(message)
Note
When using the traditional interface specified above, all messages will be marked as read immediately.
The storage object behaves almost like any other collection. You can get message at a specific index, slice it, check its length, etc. See more in the reference for Storage.
from django.contrib.messages import get_messages
storage = get_messages(request)
first_five_messages = storage[:5]
if storage:
message = storage[0]
Alternatively, this module provides a QuerySet access to the messages.
It includes extra information in the messages, like created
, read_at
and view
to specify the creation time,
when read (or null if unread), and the view who submitted the message respectively.
Using the QuerySet you will have all it’s features like filtering, aggregations, etc.
This can be access through the storage, for example:
from django.contrib.messages import get_messages
storage = get_messages(request)
queryset = storage.get_queryset() # all messages
unread_queryset = storage.get_unread_queryset() # unread messages only
Warning
When using the queryset interface, it is important to mark as seem all queried messages after use.
After every access, you will probably want to mark those messages as read in order to allow them to be cleared from the database.
This can be done manually like so:
from django.contrib.messages import get_messages
storage = get_messages(request)
queryset = storage.get_unread_queryset()
# do something with the messages...
queryset.mark_read()
Alternatively, you can use the with
operator on the storage to mark all messages as read on block exit.
For example:
from django.contrib.messages import get_messages
storage = get_messages(request)
with get_messages(request) as storage:
queryset = storage.get_unread_queryset()
# do something with the messages...
Note
When no session is available in the request, the messages are saved in a temporary storage in memory and can be accessed only throughout the same request/response process.
In this scenario, only legacy interface is available.
That means all queryset related features, such as get_queryset()
, get_unread_queryset()
, mark_read()
and the with
operator will not do practically anything.
Deleting messages
When using a persistent message storage, it is important to implement procedure for clearing out old messages.
When using sessions, messages get cleared automatically only when the appropriate session is deleted from database
due to user logout or clearsessions
command.
This behavior is not affected by the MESSAGES_USE_SESSIONS
setting.
As long as there is a session provided with the request, all the messages will be cleared when the session is cleared.
Note
Make sure to regularly run the clearsessions
command to delete any expired session and clear stale messages.
See more at the django docs https://docs.djangoproject.com/en/3.1/topics/http/sessions/#clearing-the-session-store
If you are not using Session Authentication, it is advised to setup a manual message clearing procedure, such as a scheduled deletion of all read messages created before a certain time.
Additionally, you may want to configure the MESSAGE_DELETE_READ
setting to True
at your project’s settings.py
file.
This setting will cause any read message to be deleted just after the request is done processing.
Another way is to delete messages manually in you code. This can be done using the QuerySet interface to messages:
from django.contrib.messages import get_messages
storage = get_messages(request)
queryset = storage.get_queryset()
# delete only messages that have already been read
queryset.filter(read_at__isnull=False).delete()
Note
Make sure not to delete unread messages before the user gets a chance or getting them…