Django Channels message read and unread
I am new to django channels and trying to build a chat app, I met some trouble in developing read
and unread
functioning, I hope you can give me a hand.
chat consumer has a very simple structure:
room name chat_1 is for user 1 to receive message. whoever connects to it, can send message to user 1, and database save method is defined in consumer which takes self.scope["user"]
as sender, and self.room_name
as receiver to create message record and mark it as unread
user has a friend list, by clicking on the name, load all messages, meanwhile mark all messages to read, I did this by ajax function rather than ws as user click away from talking target.
but here is one scenario, where two user is on each other's page and does not click anyone else, I need to init the message with read already when creating to database.
let's say user_1
is talking to user_22
, user_1
connect to many ws, but currently facing ws_22
to send message to user_22
. In the receive method, how can I determine whether user_22
is currently facing ws_1 which waiting for the message?
by saying facing, I does not mean connect to the websocket, user connect to many ws at the same time corresponding to their friends (each friend has a unique ws to receive message) I mean to turn to the chat bubbles page with target user by clicking user avatar.
if you are confused or stressed by any of my expression, I am sorry for troubling. however, if you have any suggestion or any thing for me to look at, I will be more than grateful.
chat consumer
class ChatConsumer(AsyncJsonWebsocketConsumer):
@staticmethod
def send_chat(pk, message):
channel_layer = get_channel_layer()
async_to_sync(channel_layer.group_send)(
'chat_{}'.format(pk),
{
'type': 'chat_message',
'message': message,
}
)
@staticmethod
@database_sync_to_async
def userOnline(pk):
user = User.objects.get(pk=pk)
user.chatProfile.online = True
user.save()
@staticmethod
@database_sync_to_async
def userOffline(pk):
user = User.objects.get(pk=pk)
user.chatProfile.online = False
user.save()
@staticmethod
@database_sync_to_async
def newText(text, style, sender_pk, receiver_pk):
msg = Message(
sender=User.objects.get(pk=sender_pk).chatProfile,
receiver=User.objects.get(pk=receiver_pk).chatProfile,
text=text,
style=style,
)
msg.save()
return msg
async def connect(self):
self.room_name = self.scope['url_route']['kwargs']['pk']
self.room_group_name = 'chat_%s' % self.room_name
await self.channel_layer.group_add(
self.room_group_name,
self.channel_name,
)
await self.accept()
user = self.scope['user']
await ChatConsumer.userOnline(user.pk)
await self.channel_layer.group_send(
'chat_{}'.format(self.room_name),
{
'type': 'online_status',
'message': 'online',
}
)
async def disconnect(self, close_code):
user = self.scope['user']
await ChatConsumer.userOffline(user.pk)
await self.channel_layer.group_send(
'chat_{}'.format(self.room_name),
{
'type': 'online_status',
'message': 'offline',
}
)
await self.channel_layer.group_discard(
self.room_group_name,
self.channel_name,
)
async def receive(self, text_data=None, bytes_data=None):
text_data_json = json.loads(text_data)
if text_data_json['type'] == 'text':
message = text_data_json['message']
style = None
try:
style = text_data_json['style']
except KeyError:
pass
'''
sender: self.scope["user"].pk
receiver: self.room_name
'''
await ChatConsumer.newText(
message,
style,
self.scope["user"].pk,
int(self.room_name),
)
await self.channel_layer.group_send(
self.room_group_name,
{
'type': 'chat_message',
'message': message,
'style': style,
}
)
async def chat_message(self, event):
await self.send(text_data=json.dumps({
'message': event['message'],
'style': event['style'],
'user': self.scope['user'].pk,
}))
async def online_status(self, event):
await self.send(text_data=json.dumps({
'type': 'online',
'message': event['message'],
'user': self.scope['user'].pk,
}))
message model
class Message(models.Model):
sender = models.ForeignKey(ChatProfile, on_delete=models.CASCADE, related_name='sent')
receiver = models.ForeignKey(ChatProfile, on_delete=models.CASCADE, related_name='received')
text = models.TextField(blank=1, null=1)
image = models.FileField(upload_to='chatprofile_image', blank=1, null=1)
file = models.FileField(upload_to='chatprofile_file', blank=1, null=1)
audio = models.BinaryField(blank=1, null=1)
createTime = models.DateTimeField(default=now)
read = models.BooleanField(default=False)
style = models.CharField(max_length=50, blank=1, null=1)
chat profile model
class ChatProfile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, related_name='chatProfile')
# mutual added relationship
friends = models.ManyToManyField(User, blank=1, related_name='friends')
online = models.BooleanField(default=False)