Hello!
I am working on a project where I need to create live communication between users. I am using Django Channel for that, but I have come across an issue where I cannot differentiate between message sender and receiver in JavaScript.
Here is a picture of what I want:
And here is the actual result from browser 1:
And here is the same result from browser 2:
In the first image, I have created two messages for a message room instance via the admin panel. It is very clear who sent the message and who received the message.
In the second image and third image, I have texted messages through the browser but the messages appear on the same side for the user that sent the messages and in the opposite side for the receiver.
How can I distinguish the sender and the receiver and place their messages on left or right side?
I am not looking for actual code, but an idea of how I can solve this issue. My “solution” was to check if the authenticated users ID match the sender/receiver ID of each Chatroom instances, and based on that separate the sender and receiver message using JS. But it clearly does not work.
JS:
// Thos document only handles the websocket connection.
class DjangoChannels {
constructor(sendMessageSelector, chatInputSelector, chatMessageSubmitSelector, messagePreviewSelector, csrftoken) {
this.sendMessage = document.getElementById(sendMessageSelector);
this.chatInput = document.getElementById(chatInputSelector);
this.chatMessageSubmit = document.getElementById(chatMessageSubmitSelector);
this.messagePreview = document.querySelectorAll(messagePreviewSelector);
this.csrftoken = csrftoken;
this.setupEventListeners();
}
setupEventListeners() {
if (this.messagePreview) {
this.messagePreview.forEach((btn) => {
btn.addEventListener("click", (e) => {
e.preventDefault();
const urlExtension = btn.dataset.urlextension;
const url = btn.dataset.url;
this.setups(urlExtension, url);
})
})
}
}
// Opening up a websocket connection
setups(urlExtension, url) {
const websocketProtocol = window.location.protocol === "https:" ? "wss" : "ws";
const wsEndpoint = `${websocketProtocol}://${window.location.host}/meddelanden/${urlExtension}/`;
this.chatSocket = new WebSocket(wsEndpoint);
// Websocket message event listener
this.chatSocket.onmessage = async (e) => {
e.preventDefault();
const response = await fetch(url, {
method: "GET",
headers: {
"X-Requested-With": "XMLHttpRequest",
},
})
if (response.ok) {
console.log("Response is OK");
const data = await response.json();
const msg = JSON.parse(e.data).message
const text_message = msg;
this.displayMessages(data.auth_user_id, data.main_user_sender, data.secondary_user_receiver, text_message)
}
};
// Websocket close event listener
this.chatSocket.onclose = (e) => {
console.log("Chat socket closed unexpectedly");
};
// Input keydown event listener
this.chatInput.focus();
this.chatInput.onkeydown = (e) => {
if (e.key === "Enter") {
e.preventDefault();
this.chatMessageSubmit.click();
}
};
// Submit button on click event listener
this.chatMessageSubmit.onclick = (e) => {
e.preventDefault();
const message = this.chatInput.value.trim();
if (message !== "") {
this.chatSocket.send(JSON.stringify({
"message": message,
"url_extension": urlExtension,
}));
}
this.chatInput.value = "";
};
}
displayMessages(auth_user_id, main_user_sender, secondary_user_receiver, text_message) {
// console.log(`The text message is: ${text_message}`)
// console.log(`Authenticated user ID is: ${auth_user_id}`)
// console.log(`Main user ID is: ${main_user_sender}`)
// console.log(`Secondary user ID is: ${secondary_user_receiver}`)
const messagesContainer = document.querySelector(".message_fields");
const messageContent = text_message;
// const timestamp = new Date(timestamp).toLocaleString(); // Format timestamp as needed
let messageHTML = '';
if (auth_user_id == main_user_sender) {
messageHTML = `
<div class="message-box message-sender">
<small>Du</small>
<div>
<div>${messageContent}</div>
<div class="message-timestamp"></div>
</div>
</div>
`;
} else {
messageHTML = `
<div class="message-box message-receiver">
<small></small> <!-- Assuming sender_username is available -->
<div>
<div>${messageContent}</div>
<div class="message-timestamp"></div>
</div>
</div>
`;
}
const newMessageDiv = document.createElement('div');
newMessageDiv.innerHTML = messageHTML;
messagesContainer.appendChild(newMessageDiv);
}
}
export default DjangoChannels
Consumer:
class ChatConsumer(AsyncWebsocketConsumer):
async def connect(self):
self.room_id = self.scope['url_route']['kwargs']['room_id'] # Find the room id from the connection scope
await self.channel_layer.group_add(
self.room_id,
self.channel_name,
)
await self.accept()
await self.send(text_data=json.dumps({
"type": "connection_established",
"succesful_connection_message": "You are now connected!",
}))
async def receive(self, text_data):
text_data_json = json.loads(text_data)
message = text_data_json["message"].strip()
url_extension = text_data_json["url_extension"]
# Register the message in the database asynchronously
# await self.register_message(message, url_extension)
await self.channel_layer.group_send(
self.room_id,
{
'type': 'send_message',
'message': message,
}
)
async def disconnect(self, close_code):
await self.channel_layer.group_discard(self.room_id, self.channel_name)
# @database_sync_to_async
# def register_message(self, message, url_extension):
# chat_room = Chatroom.objects.get(url_extension=url_extension)
# chat_message = ChatMessage.objects.create(room=chat_room)
async def send_message(self, event):
message = event['message']
await self.send(text_data=json.dumps({
'message': message
}))
AJAX view:
def renderChatMessages(request, chatroom_id):
if request.headers.get("X-Requested-With") == "XMLHttpRequest":
if request.method == "GET":
try:
chatroom = get_object_or_404(Chatroom, pk=chatroom_id)
chatroom_messages = chatroom.chatroom_messages.all()
auth_user_id = request.user.id
print(auth_user_id)
main_user_sender = chatroom.sender.pk
secondary_user_receiver = chatroom.receiver.pk
serialized_messages = serialize('json', chatroom_messages)
return JsonResponse({
"chatroomMessages": serialized_messages,
"auth_user_id": auth_user_id,
"main_user_sender": main_user_sender,
"secondary_user_receiver": secondary_user_receiver,
}, status=200)
except json.JSONDecodeError:
return JsonResponse({"error": "Invalid JSON request"}, status=500)
else:
return JsonResponse({"error": "Invalid request"}, status=400)
Model (Ignore the method for URL extension, I am changing this with Django-sesame soon):
class Chatroom(models.Model):
room = models.ForeignKey(Room, on_delete=models.CASCADE, blank=True, null=True)
chatroom = models.TextField(_("Meddelande"), max_length=100, blank=True)
sender = models.ForeignKey(Member, on_delete=models.CASCADE, related_name="chatroom_creator", blank=False)
receiver = models.ForeignKey(Member, on_delete=models.CASCADE, related_name="chatroom_receiver", blank=False)
timestamp = models.DateTimeField(_("Skapad"), auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
url_extension = models.CharField(_("ULR förlänging"), max_length=settings.URL_EXTENSION_LENGTH, blank=False, unique=True)
class Meta:
ordering = ["-updated"]
def __str__(self):
return self.chatroom
def get_profilepage(self):
return reverse("profilepage_app:profile-redirect", args=[self.room.member.username_slug])
def save(self, *args, **kwargs):
if not self.url_extension: # If URL extension is empty
self.url_extension = get_random_string(length=settings.URL_EXTENSION_LENGTH)
try:
super().save(*args, **kwargs)
except IntegrityError: # If a non-unique URL extension is generated
self.url_extension = get_random_string(length=settings.URL_EXTENSION_LENGTH)
super().save(*args, **kwargs)
class ChatMessage(models.Model):
room = models.ForeignKey(Chatroom, on_delete=models.CASCADE, related_name="chatroom_messages")
sender = models.ForeignKey(Member, on_delete=models.CASCADE, related_name="chatmessage_sender", null=False, blank=False, default="")
receiver = models.ForeignKey(Member, on_delete=models.CASCADE, related_name="chatmessage_receiver", null=False, blank=False, default = "")
message = models.TextField(blank=False, max_length=settings.MAX_CHATMESSAGE_LENGTH)
timestamp = models.DateTimeField(_("Skapad"), auto_now_add=True)
def __str__(self):
return str(f"{self.sender.username} - {self.message}")
class Meta:
ordering = ['timestamp']



