I'm using this solution for save messages to DB Django channels: Save messages to database
But I have a problem with duplicates (in DB) when the user (message's author) has two or more tabs opened in the browser with same chat room.
What's wrong? Please help!
import json
from channels.db import database_sync_to_async
from channels.generic.websocket import AsyncWebsocketConsumer
from .models import Message
class ChatConsumer(AsyncWebsocketConsumer):
@database_sync_to_async
def create_chat(self, msg, sender):
return Message.objects.create(sender=sender, msg=msg)
async def connect(self):
self.room_name = self.scope['url_route']['kwargs']['room_name']
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()
async def disconnect(self, close_code):
await self.channel_layer.group_discard(self.room_group_name, self.channel_name)
async def receive(self, text_data):
text_data_json = json.loads(text_data)
message = text_data_json['message']
sender = text_data_json['sender']
await self.channel_layer.group_send(self.room_group_name, {
'type': 'chat_message',
'message': message,
'sender': sender
})
async def chat_message(self, event):
message = event['message']
sender = event['sender']
new_msg = await self.create_chat(sender, message) # It is necessary to await creation of messages
await self.send(text_data=json.dumps({
'message': new_msg.message,
'sender': new_msg.sender
}))
Solution is here. Don't call create_chat (put data to DB) from the function witch send message to WebSocket (to each opened connection / opened browser's tabs). Just call it from receive function.
# Receive message from WebSocket
async def receive(self, text_data):
text_data_json = json.loads(text_data)
message = text_data_json['message']
sender = text_data_json['username']
case = text_data_json['case_id']
chat_type = text_data_json['chat_type']
@sync_to_async
def get_user(sender):
return User.objects.get(username=sender)
@sync_to_async
def get_case(case):
return Case.objects.get(id=case)
user_obj = await get_user(sender)
case_obj = await get_case(case)
new_msg = await self.create_chat(user_obj, message, case_obj, chat_type)
# Send message to room group
await self.channel_layer.group_send(
self.room_group_name, {
'type': 'chat_message',
'message': message,
'username': sender,
'case':case,
'chat_type':chat_type,
'time': new_msg.creted_time,
}
)