13👍
One easy way to implement a notification system can be:
When you want to show a new message, manipulate HTML using JS as soon as you get a message on the websocket. And whenever the element has been interacted with, which means the user has read the notification, send a message back to server using the websocket.
Your Notification
can have ForeignKeys
to user and the message along with a BooleanField
for read status. Whenever you are sending the message to the user, you should append the notification_id along the message,
#consumer.py
async def websocket_receive(self, event):
# when a message is received from the websocket
print("receive", event)
message_type = event.get('type', None) #check message type, act accordingly
if message_type == "notification_read":
# Update the notification read status flag in Notification model.
notification = Notification.object.get(id=notification_id)
notification.notification_read = True
notification.save() #commit to DB
print("notification read")
front_text = event.get('text', None)
if front_text is not None:
loaded_dict_data = json.loads(front_text)
msg = loaded_dict_data.get('message')
user = self.scope['user']
username = 'default'
if user.is_authenticated:
username = user.username
myResponse = {
'message': msg,
'username': username,
'notification': notification_id # send a unique identifier for the notification
}
...
On the client side,
// thread.html
socket.onmessage = function(e) {
var data = JSON.parse(event.data);
// Find the notification icon/button/whatever and show a red dot, add the notification_id to element as id or data attribute.
}
...
$(#notification-element).on("click", function(){
data = {"type":"notification_read", "username": username, "notification_id": notification_id};
socket.send(JSON.stringify(data));
});
You can mark individual/all unread notifications as read according to your need.
I did something similar for a training project, you can check that out for ideas. Github link.
0👍
I couldn’t mark this as a duplicate, because there is a bounty on it. But the solution is, you need more than two models. According to this post, your models.py
should look something like this:
class MessageThread(models.Model):
title = models.CharField()
clients = models.ManyToManyField(User, blank=True)
class Message(models.Model):
date = models.DateField()
text = models.CharField()
thread = models.ForeignKey('messaging.MessageThread', on_delete=models.CASCADE)
sender = models.ForeignKey(User, on_delete=models.SET_NULL)
Your consumers.py
should look like this:
class ChatConsumer(WebSocketConsumer):
def connect(self):
if self.scope['user'].is_authenticated:
self.accept()
# add connection to existing groups
for thread in MessageThread.objects.filter(clients=self.scope['user']).values('id'):
async_to_sync(self.channel_layer.group_add)(thread.id, self.channel_name)
# store client channel name in the user session
self.scope['session']['channel_name'] = self.channel_name
self.scope['session'].save()
def disconnect(self, close_code):
# remove channel name from session
if self.scope['user'].is_authenticated:
if 'channel_name' in self.scope['session']:
del self.scope['session']['channel_name']
self.scope['session'].save()
async_to_sync(self.channel_layer.group_discard)(self.scope['user'].id, self.channel_name)
- Cannot solve mod_wsgi exception in Django setup
- Django test client response context None
- Django. Jquery. escaping string with quotes error
- Setting HTTP_REFERER header in Django test
- Django-Rest-Framework Relationships & Hyperlinked API issues