我正在考虑创建一个模型来处理保存和创建组,如下所示:
# Something like this perhaps...
class OneOnOneRoom(models.Model):
room_name = models.CharField(max_length = 100, unique=True)
sender = models.ForeignKey(User, null=True, on_delete=models.CASCADE)
receiver = models.ForeignKey(User, null=True, on_delete=models.CASCADE)
def __str__(self):
return f'Group {self.room_name} initiated by {self.sender} for {self.receiver}'
然后在我的消费者的连接方法中,我需要以某种方式创建两个房间,这样我就可以广播来自用户 A 或用户 B 的所有消息以发送到两个房间,以便两个用户都可以看到彼此的消息。
因此,如果用户 A 为
http://localhost:8000:chat/B
并且用户 B 为 http://localhost:8000:chat/A
;用户A应该向自己的通道和B的通道发送数据;用户 B 应该将数据发送到自己的通道和 B 的通道。
这是一个很好的解决方案吗?我现在想不出任何更好的解决方案——无论哪种方式,我都找不到在频道中一次实际发送到多个频道的方法。有什么建议吗?
我一直在尝试和思考:
#asgi.py
application = ProtocolTypeRouter({
"http": django_asgi_app,
"websocket": AllowedHostsOriginValidator(
AuthMiddlewareStack(
URLRouter([
re_path(r"ws/chat/(?P<room_name>\w+)/$", ChatConsumer.as_asgi()),
])
)
),
})
#urls.py
urlpatterns = [
path('<str:room_name>/', room),
]
#views.py
def room(request, room_name):
return render(request, 'chat/room.html', {'room_name': room_name})
#chat/room.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<title>Chat Room</title>
</head>
<body>
<div id="chat-log">
<!-- Messages will be displayed here -->
</div>
<form id="chat-form">
<input id="chat-message-input" type="text" size="100" autocomplete="off">
<input id="chat-message-submit" type="submit" value="Send">
</form>
{{ room_name|json_script:"room-name" }}
<script>
const roomName = JSON.parse(document.getElementById('room-name').textContent);
const chatSocket = new WebSocket(
'ws://' + window.location.host + '/ws/chat/' + roomName + '/'
);
console.log(chatSocket)
document.querySelector('#chat-form').onsubmit = (e) => {
e.preventDefault();
const messageInputDom = document.querySelector('#chat-message-input');
const message = messageInputDom.value;
chatSocket.send(JSON.stringify({
'message': message
}));
messageInputDom.value = '';
};
chatSocket.onmessage = (e) => {
const data = JSON.parse(e.data);
const chatLog = document.getElementById('chat-log');
const messageDiv = document.createElement('div');
messageDiv.textContent = `${data.user}: ${data.message} | Posted : ${data.date}`;
chatLog.appendChild(messageDiv);
};
chatSocket.onclose = (e) => {
console.error('Chat socket closed unexpectedly');
};
</script>
</body>
</html>
#consumers.py
class ChatConsumer(AsyncWebsocketConsumer):
async def connect(self):
current_user = self.scope['user']
other_user = self.scope['url_route']['kwargs']['room_name']
# Should send to both of these,
# self.room_group_name = f'group_{current_user}_{other_user}'
# self.room_group_name = f'group_{other_user}_{current_user}'
# But the room_group_name should change based on who is logged in.
# If user A then f'group_{current_user}_{other_user}' example and then the opposite user B
if not await self.check_room_exists(room_name=self.room_group_name):
await self.create_one_on_one_room(sender=current_user, receiver=other_user, room_name=self.room_group_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"]
# Data from client side comes here but it only sends to one of the defined room_group_name[s]
await self.channel_layer.group_send(
self.room_group_name, {"type": "chat_message", "message" : message})
async def chat_message(self, event):
user = self.scope["user"]
message = event["message"]
date = str(datetime.now().strftime("%c"))
await self.send(text_data=json.dumps({"user": user.username,"date": date, "message": message}))
@database_sync_to_async
def get_user(self, username):
return User.objects.get(username=username)
@database_sync_to_async
def check_room_exists(self, room_name):
return OneOnOneRoom.objects.filter(room_name=room_name).exists()
@database_sync_to_async
def create_one_on_one_room(self, current_user, other_user, room_name):
return OneOnOneRoom.objects.create(sender=current_user, receiver=other_user, room_name=room_name)
@database_sync_to_async
def get_one_on_one_room(self, room_name):
return OneOnOneRoom.objects.get(room_name=room_name)
编辑: 除非有更好的方法来创建一对一聊天,然后告诉我。