[英]One Django Channels websocket consumer used across whole site?
I have a Django project that uses WebSockets and one consumer ( ChatConsumer
) for both the chat and notification portion of the application. 我有一个使用WebSockets和一个使用者(
ChatConsumer
)进行应用程序的聊天和通知部分的Django项目。
I had routing.py
set to url(r"^messages/(?P<username>[\\w.@+-]+)", ChatConsumer)
however because notifications are also dependent on the websocket, they need to be accessed from any page on the site. 我将
routing.py
设置为url(r"^messages/(?P<username>[\\w.@+-]+)", ChatConsumer)
但是由于通知也依赖于websocket,因此需要从以下位置访问它们网站上的任何页面。
The reason is that when a user clicks on the notification, it is marked as read
using 原因是,当用户单击通知时,使用标记为已
read
socket.send(JSON.stringify(data));
Right now notifications only work when a user is on the /messages/<username>/
URL. 现在,通知仅在用户位于
/messages/<username>/
URL上时起作用。
If I change routing.py
to account for the whole site, ( url(r"^", ChatConsumer)
), I obviously get a problem 如果我将
routing.py
更改为占整个站点( url(r"^", ChatConsumer)
),我显然会遇到问题
File "./consumers.py" in websocket_connect
other_user = self.scope['url_route']['kwargs']['username']
'username'
Is there a simple way of resolving this? 有解决此问题的简单方法吗? Because correct me if I'm wrong but I don't think writing a new consumer is appropriate since the notifications and chat are deeply intertwined?
因为如果我错了就纠正我,但是由于通知和聊天紧密地纠缠在一起,所以我认为写一个新的使用者不合适吗?
consumers.py users.py
class ChatConsumer(AsyncConsumer):
async def websocket_connect(self, event):
other_user = self.scope['url_route']['kwargs']['username']
me = self.scope['user']
thread_obj = await self.get_thread(me, other_user)
self.thread_obj = thread_obj
chat_room = f"thread_{thread_obj.id}"
self.chat_room = chat_room
# below creates the chatroom
await self.channel_layer.group_add(
chat_room,
self.channel_name
)
await self.send({
"type": "websocket.accept"
})
async def websocket_receive(self, event):
# when a message is recieved from the websocket
print("receive", event)
message_type = json.loads(event.get('text','{}')).get('type')
if message_type == "notification_read":
user = self.scope['user']
username = user.username if user.is_authenticated else 'default'
# Update the notification read status flag in Notification model.
notification = Notification.objects.filter(notification_user=user).update(notification_read=True)
print("notification read")
return
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 = user.username if user.is_authenticated else 'default'
notification_id = 'default'
myResponse = {
'message': msg,
'username': username,
'notification': notification_id,
}
print(myResponse)
await self.create_chat_message(user, msg)
other_user = self.scope['url_route']['kwargs']['username']
other_user = User.objects.get(username=other_user)
await self.create_notification(other_user, msg)
# broadcasts the message event to be sent, the group send layer
# triggers the chat_message function for all of the group (chat_room)
await self.channel_layer.group_send(
self.chat_room,
{
'type': 'chat_message',
'text': json.dumps(myResponse)
}
)
# chat_method is a custom method name that we made
async def chat_message(self, event):
# sends the actual message
await self.send({
'type': 'websocket.send',
'text': event['text']
})
async def websocket_disconnect(self, event):
# when the socket disconnects
print('disconnected', event)
@database_sync_to_async
def get_thread(self, user, other_username):
return Thread.objects.get_or_new(user, other_username)[0]
@database_sync_to_async
def create_chat_message(self, me, msg):
thread_obj = self.thread_obj
return ChatMessage.objects.create(thread=thread_obj, user=me, message=msg)
@database_sync_to_async
def create_notification(self, other_user, msg):
last_chat = ChatMessage.objects.latest('id')
created_notification = Notification.objects.create(notification_user=other_user, notification_chat=last_chat)
return created_notification
base.html base.html
<script>
$(document).ready(function() {
// $('div[id^="notification-"]')
$("#notificationLink").click(function() {
$('span[id^="notification"]').each(function() {
var username = '{{ request.user.username }}'
var data = {
"type": "notification_read",
"username": username,
}
socket.send(JSON.stringify(data));
});
});
</script>
<script>
...
var endpoint = wsStart + loc.host + loc.pathname
var socket = new ReconnectingWebSocket(endpoint)
// all the websocket scripts - client side*
...
</script>
I think you should send other_user with message so it should be like that 我认为您应该向other_user发送消息,所以应该这样
msg = loaded_dict_data.get('message')
other_user = loaded_dict_data.get('other_user')
so you no more need to use self.scope['url_route']['kwargs']['username'] 因此您不再需要使用self.scope ['url_route'] ['kwargs'] ['username']
BTW can you share the code on github because i prepare to do something like this and i think your project will help me alot 顺便说一句,您能在github上共享代码吗,因为我准备做这样的事情,并且我认为您的项目会对我有很大帮助
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.