Why are my messages not showing in real-time using HTMX and WebSockets in Django?

I'm building a simple two-way chat system as a part of my web-app using HTMX WebSockets (htmx-ext-ws). The goal is to display incoming messages in real time without requiring a manual page refresh.

The setup mostly works — messages are being saved to the database, and the WebSocket connection seems to establish correctly. However, new messages only appear after a page reload, and not in real time as expected.

Here’s an overview of what I have:

#chat.html

{% load static %}

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Chat</title>
    <script src="https://unpkg.com/htmx.org@1.9.12"></script>
    <script src="https://unpkg.com/hyperscript.org@0.9.12"></script>
    <script src="https://unpkg.com/htmx-ext-ws@2.0.2"></script>
    <link rel="stylesheet" href="{% static 'css/chat.css' %}">
</head>
<body>
    <div class="chat-container">
        <div class="chat-header">
            Chat Room
        </div>
        <div class="chat_messages" >
            {% for message in messages %}
            <div class="message-row {% if message.author.user == user %}my-message{% else %}other-message{% endif %}">
              {% include "chat_rt/chat_message.html" %}  
            </div>
            {% empty %}
            <div>No messages yet.</div>
            {% endfor %}
        </div>
        <form class="chat-input-area" id="chat-form" autocomplete="off"
              method="POST"
              hx-ext="ws"
              ws-connect="ws://127.0.0.1:8000/ws/chatroom/private-chat" 
              ws-send
              _="on htmx:wsAfterSend set #chat-input.value to ''">
            {% csrf_token %}
            {{ form.body }}
            <button type="submit">Send</button>
        </form>
    </div>
    <script src="{% static 'js/chat2.js' %}"></script>
</body>
</html>
#chat_message.html

{% if message.author.user == user %}
    <div class="message-content">
        <div class="message-meta right">
            <span class="time">{{ message.created|date:"H:i" }}</span>
        </div>
        <div class="body">{{ message.body }}</div>
    </div>
{% else %}
    <div class="message-content">
        <img class="profile-pic" src="{{ message.author.profile_pic.url }}" alt="{{ message.author.username }}">
        <div>
            <div class="message-meta left">
                <span class="author">{{ message.author.username }}</span>
                <span class="time">{{ message.created|date:"H:i" }}</span>
            </div>
            <div class="body">{{ message.body }}</div>
        </div>
    </div>
{% endif %}
 
#chat_message_p.html(the partial)

<div id="chat-messages" hx-swap-oob="beforeend">
  {% include "chat_rt/chat_message.html" %}
</div>


#consumers.py

from channels.generic.websocket import WebsocketConsumer
from django.shortcuts import get_object_or_404
from django.template.loader import render_to_string
import json

from .models import ChatGroup, GroupMessage

class ChatroomConsumer(WebsocketConsumer):
    def connect(self):
        print("WebSocket connecting...")
        self.user = self.scope['user']
        self.chatroom = get_object_or_404(ChatGroup, group_name='private_chat') 
        print("WebSocket connected!")
        self.accept()

    def receive(self, text_data):
        print("Received from client:", text_data)
        text_data_json = json.loads(text_data)
        body = text_data_json['body']

        message = GroupMessage.objects.create(
            body=body,
            author=self.user.profile,
            group=self.chatroom,
        )

        context = {
            'message': message,
            'user': self.user,
        }

        html = render_to_string("chat_rt/partials/chat_message_p.html", context=context)

        try:
            self.send(text_data=json.dumps({
                "content": html,
                "target": "#chat-messages",
                "swap": "beforeend"
            }))
            print("WebSocket send successful")
        except Exception as e:
            print("WebSocket send failed:", e)



Вернуться на верх