Django channels + HTMX -> notification messages framework
I'd like to implement a notification framework for Django that uses channels/websockets and HTMX. But I don't get how to do that. Some things work, some are extremely complicated n my mind at least. Here's the code:
from asgiref.sync import async_to_sync
from channels.generic.websocket import WebsocketConsumer
from channels.layers import get_channel_layer
from django.contrib import messages
from django.template.loader import get_template
from medux.common.models import User
class NotificationConsumer(WebsocketConsumer):
def connect(self):
self.user = self.scope["user"]
if not self.user.is_authenticated:
self.close()
return
# create a group "user-<username>"
async_to_sync(self.channel_layer.group_add)(
f"user-{self.user.username}",
self.channel_name,
)
self.accept()
def disconnect(self, close_code):
async_to_sync(self.channel_layer.group_discard)(
f"user-{self.user.username}",
self.channel_name,
)
def notify(self, event: dict):
html = get_template("common/toast.html").render(
context={"message": event["message"]}
)
self.send(text_data=html)
<div hx-ext="ws" ws-connect="/ws/messages">
<div id="toasts" class="toast-container position-fixed bottom-0 end-0 p-3 pb-5">
{% for message in messages %}
<div
id="toasts"
hx-swap-oob="beforeend">
<div
data-toast-template
class="toast align-items-center border-0 show"
role="alert"
aria-live="assertive"
aria-atomic="true">
{# header here #}
<div data-toast-body class="toast-body">{{ message }}</div>
<button type="button" class="btn-close btn-close-white me-2 m-auto" data-bs-dismiss="toast" aria-label="Close"></button>
</div>
</div>
{% endfor %}
</div>
</div>
The client connects to the consumer, and if I write a small `self.send(text_data="foo")
AFAIK, I have to send an "high level" event to the consumer with the type "notify", so the notify()
method is called. So this would be a code called anywhere in a view e.g.:
from asgiref.sync import async_to_sync
from channels.layers import get_channel_layer
channel_layer = get_channel_layer()
async_to_sync(channel_layer.group_send)(
"user-christian",
{"type": "notify", "message": "<div id='toasts' hx-swap-oob='beforeend'>blah</div>"}
)
I don't step through the internals of channels, no matter how often I read the docs..
The docs how to use group_add
and group_send
are sparse, and I am sure I am using them wrong.
Could anyone give me some hints here? In the next step, I would replace Django's messaging framework with this solution in my application.
I got that things to work with Turbo Django, which is quite convenient to work with, but lacks triggers like HTMX that let me iniciate AJAX calls like hx-post or hx-get.