Message framework integration
Django Messages
Tetra integrates deeply Django's messaging framework. A traditional Django approach is to fetch all messages into the template and display them.
In a component based layout as Tetra describes, where individual components independently make AJAX calls and update themselves, it is not as easy. You may have one component that gets the messages, but it is not notified about that when another component calls a method. Then, all messages would be stuck in the wrong response/component, so this doesn't help. Even when notifying the "messages" component so that it could get the new messages, would help, it would even make things worse, as there would be race conditions when 2 components update, and the messages component updates itself too twice, overwriting the first message with the proceeding one.
Tetra Messages — brought by events
So, the messaging must be kept independently on the client. Tetra tries to solve this by providing new messages, whenever they occur, with any call of any component, through the middleware. TetraMiddleware
and Tetra's client JavaScript part process all messages and convert them into JavaScript objects that are then sent individually via a fired event: tetra:new-message
.
You can react on it in any component, using client side/Alpine.js or server side code:
<div x-data="{bell: false}" @tetra:new-message="bell=true">
<i class="bi bi-bell" x-show="bell"></i>
</div>
Since Tetra provides a @public.subscribe modifier, you can even react on the server on that:
from django.contrib.messages import Message
class MyComponent(Component):
@public.subscribe("tetra:new-message")
def message_added(self, message:Message):
...
Note
This makes only sense in certain scenarios, as the roundtrips Message generation -> Middleware -> Client event emitting -> AJAX call of backend method is a bit much for just reacting on a message.
Tetra takes care of the serialization/transition from a Django Message
to a full Javascript object with all necessary data available, including a boolean "dismissible" attribute.
Message Attributes
Django knows only three attributes: message:str
, level:int
and extra_tags:str
, and dynamically builds the tags and level_tags as properties from them.
// Message anatomy
{
message: "Successfully saved File",
uid: "5d68f405-8427-4e04-80b7-0996bf5e3629",
level: 25,
level_tag: "bg-success-lt",
tags: "success dismissible",
extra_tags: "dismissible",
dismissible: true
}
The .uid
attribute
In Django, there is no UID in messages. You could change your Message/Storage type by using settings.MESSAGE_STORAGE
, but this is not necessary. We need the UID of each message only on the client.
So each message gets an UID during the middleware transition, so it can be displayed and deleted individually. Just make sure to include the MessageMiddleware, and TetraMiddleware. The messages are transported via a special T-Messages
response header.
The .dismissible
attribute: a special case
There are cases where messages should be "sticky". In this case, you can add the extra_tag "dismissible" to the message, and Tetra will treat it specially:
In this case, the message will get a boolean attribute .dismissible
on the client, so you could filter them out easier.