I have created django consumers.py and a frontend in html and css to disply messages sent by a user, the profile picture of the sender and the username of the sender but anytime i open the browser, the message displays well and the username appears well but the time since always appear as undefined even though i printed the time stamp from the websocket and it shows the actual timp. ususally when i send a message, i see the received timestamp on the developer console but immediately i refresh the page it changes to undefine, i simply want to be able to display the time elapsed since a essage was sent, example X seconds ago, X minutes ago, X hours ago my timestamp field is using timezone.now, Please i want a user to see the timesince a message was sent, the tmplate filere timesince isnt working though
this is my consumers.py
import os import json from channels.generic.websocket import AsyncWebsocketConsumer from django.contrib.auth import get_user_model from django.conf import settings from channels.db import database_sync_to_async from virtualrooms.models import VirtualRoom from .models import Interaction from django.templatetags.static import static from datetime import datetime User = get_user_model() class DiscussionRoomConsumer(AsyncWebsocketConsumer): async def connect(self): self.room_name = self.scope['url_route']['kwargs']['room_name'] self.room_group_name = f"discussion_room_{self.room_name}" # Join room group await self.channel_layer.group_add( self.room_group_name, self.channel_name ) await self.accept() # Get or create the VirtualRoom instance based on the provided room_name virtual_room = await self.get_virtual_room() if virtual_room is not None: # Send existing messages and old messages to the new user old_messages = await self.get_old_messages(virtual_room) for message in old_messages: await self.send(text_data=json.dumps({ 'message': message['content'], 'username': await self.get_username(message['user']), 'user_picture': await self.get_user_profile_picture(message['user']), })) async def disconnect(self, close_code): # Leave room group await self.channel_layer.group_discard( self.room_group_name, self.channel_name ) # Receive message from WebSocket async def receive(self, text_data): text_data_json = json.loads(text_data) message = text_data_json['message'] user_id = self.scope["user"].id # Get the VirtualRoom instance based on the extracted room name asynchronously virtual_room = await self.get_virtual_room() # Check if the VirtualRoom instance exists if virtual_room: # Save message to the database with the VirtualRoom instance asynchronously await self.save_interaction_to_database(user_id, virtual_room, message) # Send message to the room group time_stamp = datetime.now().isoformat() username = await self.get_username(user_id) user_picture = await self.get_user_profile_picture(user_id) # Log the entire message data print("Sending message data:", { 'message': message, 'username': username, 'user_picture': user_picture, 'time_stamp': time_stamp, }) await self.channel_layer.group_send( self.room_group_name, { 'type': 'chat.message', 'message': message, 'username': username, 'user_picture': user_picture, 'time_stamp': time_stamp, } ) else: # Handle the case where the VirtualRoom does not exist print(f"VirtualRoom with slug '{self.room_name}' does not exist.") @database_sync_to_async def save_interaction_to_database(self, user_id, virtual_room, message): # Save the message to the database with the VirtualRoom instance Interaction.objects.create( user_id=user_id, room_name=virtual_room, content=message ) @database_sync_to_async def get_old_messages(self, virtual_room): # Fetch old messages based on the VirtualRoom return list(Interaction.objects.filter(room_name=virtual_room).order_by('time_stamp').values('user', 'content')) @database_sync_to_async def get_username(self, user_id): try: user = User.objects.get(id=user_id) return user.username except User.DoesNotExist: return None @database_sync_to_async def get_user_profile_picture(self, user_id): try: user = User.objects.get(id=user_id) # Check if the user has a profile picture if hasattr(user, 'user_picture') and user.user_picture: user_picture = user.user_picture # Use Django storage to get the correct file path image_path = user_picture.path if os.path.isfile(image_path): # Return the actual user picture URL if the image file exists return user_picture.url else: # Log that the image file doesn't exist and return the default avatar print(f"Image file for user {user_id} does not exist. Using default avatar.") return static('images/avatar.svg') else: # Log that the user does not have a profile picture and return the default avatar print(f"User {user_id} does not have a profile picture. Using default avatar.") return static('images/avatar.svg') except User.DoesNotExist: # Log that the user does not exist and return the default avatar print(f"User {user_id} does not exist. Using default avatar.") return static('images/avatar.svg') @database_sync_to_async def get_virtual_room(self): try: return VirtualRoom.objects.get(slug__iexact=self.room_name) except VirtualRoom.DoesNotExist: return None # Receive message from the room group async def chat_message(self, event): message = event['message'] username = event['username'] user_picture = event['user_picture'] time_stamp = event['time_stamp'] print(f"Sending message with timestamp: {time_stamp}") # Send the message to WebSocket await self.send(text_data=json.dumps({ 'message': message, 'username': username, 'user_picture': user_picture, 'time_stamp': time_stamp, })) and this is my frontend: {% load static %} Discussion Room {% for message in messages %}
{{ message.username }}: {{ message.message }} {{ message.time_stamp|timesince }} {% endfor %} Send // Get the room name from the URL const pathArray = window.location.pathname.split('/'); const roomNameIndex = pathArray.indexOf('discussions') + 1; const roomName = pathArray[roomNameIndex].split('@')[1]; // Log the extracted room name console.log('Extracted room name:', roomName); // Create a new WebSocket connection const socket = new WebSocket(`ws://${window.location.host}/ws/discussions/${roomName}/`); socket.onmessage = function(event) { const data = JSON.parse(event.data); console.log('Received data:', data); displayMessage(data.user_picture, data.username, data.message, data.time_stamp); // Save timestamp to local storage localStorage.setItem('lastTimestamp', data.time_stamp); }; function sendMessage() { const message = document.getElementById('message-input').value; if (message.trim() !== '') { socket.send(JSON.stringify({'message': message})); document.getElementById('message-input').value = ''; } } function displayMessage(userPicture, username, message, timestamp) { console.log('Received timestamp:', timestamp); console.log('Received user picture:', userPicture); localStorage.setItem('lastTimestamp', timestamp); const messageDiv = document.createElement('div'); // Set the userPicture URL const imageUrl = userPicture || '/static/images/avatar.svg'; //console.log('Selected image URL:', imageUrl); const imgElement = new Image(); imgElement.src = imageUrl; // Add an event listener to handle image load errors imgElement.addEventListener('error', function() { //console.warn('Error loading image. Using default avatar.'); messageDiv.innerHTML = `
${message}`; document.getElementById('chat-box').appendChild(messageDiv); }); // Add an event listener to handle image load success imgElement.addEventListener('load', function() { imgElement.className = 'user-profile-img'; // Add this line messageDiv.innerHTML = `
${username}: ${message}`; document.getElementById('chat-box').appendChild(messageDiv); }); } const storedTimestamp = localStorage.getItem('lastTimestamp'); if (storedTimestamp) { console.log('Retrieved timestamp from local storage:', storedTimestamp); }
Источник: https://stackoverflow.com/questions/780 ... javascript