Django Channels消息通知异常:通知显示在发送方而非接收方页面
Django Channels 通知仅发送方可见问题排查
我正在开发一个带通知功能的Django实时消息模块,设定对话仅限2名用户,每条消息发送后需推送通知,但目前通知仅显示在发送方页面,接收方看不到。以下是实现代码:
consumers.py
import json from channels.generic.websocket import AsyncWebsocketConsumer from channels.db import database_sync_to_async from .models import Chat, ChatRoom from accounts.models import User from asgiref.sync import sync_to_async from django.contrib.auth import get_user_model from django.shortcuts import get_object_or_404 from asgiref.sync import async_to_sync class ChatConsumer(AsyncWebsocketConsumer): async def connect(self): self.room_id = self.scope['url_route']['kwargs']['room_id'] self.room_group_name = 'chat_%s' % self.room_id 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'] recipient = text_data_json['recipient'] self.user_id = self.scope['user'].id # Find room object room = await database_sync_to_async(ChatRoom.objects.get)(pk=self.room_id) print('ok1') # Create new chat object chat = Chat( content=message, sender=self.scope['user'], room=room, ) print('ok2') await database_sync_to_async(chat.save)() print("ok3") # get the recipient user recipient_user = await database_sync_to_async(User.objects.get)(id=recipient) print("ok4") await sync_to_async(chat.recipient.add)(recipient_user.id) print("ok5") await database_sync_to_async(chat.save)() await self.channel_layer.group_send( self.room_group_name, { 'type': 'chat_message', 'message': message, 'user_id': self.user_id }) # Send a notification to the recipient await self.channel_layer.send( recipient_user.username, { 'type': 'notification', 'message': message } ) await self.send_notification(f'New message from {self.user_id}') print('notification has been created') async def chat_message(self, event): message = event['message'] user_id = event['user_id'] await self.send(text_data=json.dumps({ 'message': message, 'user_id': user_id })) async def send_notification(self, message): await self.send(text_data=json.dumps({ 'type': 'notification', 'message':message }))
room.js
chatSocket.onmessage = function(e) { const data = JSON.parse(e.data); console.log("data",data) console.log("datatype",data.type) var message_type = data.type; console.log("message type",message_type) if(message_type === 'notification'){ $("#notification-bar2").text(data.message); $("#notification-bar2").show(); } if(message_type !== 'notification'){ const messageElement = document.createElement('div') const userId = data['user_id'] const loggedInUserId = JSON.parse(document.getElementById('user_id').textContent) console.log(loggedInUserId) messageElement.innerText = data.message if (userId === loggedInUserId) { messageElement.classList.add( 'relative', 'max-w-xl', 'px-4', 'py-2', 'text-gray-700', 'bg-gray-100','rounded', 'shadow','flex', 'justify-end','message', 'sender','block') } else { messageElement.classList.add('relative', 'max-w-xl', 'px-4', 'py-2', 'text-gray-700', 'bg-gray-100','rounded', 'shadow','flex', 'justify-start','message', 'receiver','block') } chatLog.appendChild(messageElement) if (document.querySelector('#emptyText')) { document.querySelector('#emptyText').remove() } } };
核心问题与修复方案
1. 通道目标错误
你用recipient_user.username作为通道名称发送通知,但接收方的WebSocket连接并未监听这个通道,也没有加入对应的组。Channels中channel_layer.send只能发送给已存在的通道实例,而你没有为接收方绑定这个名称的通道。
2. 通知发送逻辑错误
你调用self.send_notification()是直接给当前连接(发送方)发通知,接收方的通知需要通过正确的组或通道推送,同时消费者需要对应处理方法。
3. 缺失通知处理方法
当前ChatConsumer没有定义notification类型的消息处理方法,即使消息送到正确通道,也无法转发给前端。
具体修复步骤
步骤1:为每个用户创建专属通知组
在connect方法中,让用户加入以自身ID命名的组(比用户名更可靠):
async def connect(self): self.room_id = self.scope['url_route']['kwargs']['room_id'] self.room_group_name = 'chat_%s' % self.room_id # 新增:加入用户专属通知组 self.user_group_name = f'user_{self.scope["user"].id}' await self.channel_layer.group_add( self.user_group_name, self.channel_name ) await self.channel_layer.group_add( self.room_group_name, self.channel_name ) await self.accept()
步骤2:修改通知发送逻辑
替换原有的channel_layer.send为group_send,发送到接收方的专属组:
# 替换原通知发送代码 await self.channel_layer.group_send( f'user_{recipient_user.id}', { 'type': 'notification_message', 'message': f'New message from {self.scope["user"].username}' } ) # 移除原有的await self.send_notification(...),避免重复给发送方发通知
步骤3:添加通知处理方法
在ChatConsumer中新增处理通知的方法:
async def notification_message(self, event): message = event['message'] await self.send(text_data=json.dumps({ 'type': 'notification', 'message': message }))
步骤4:优化关联用户的代码
chat.recipient.add可以直接传用户对象,不需要转ID:
await database_sync_to_async(chat.recipient.add)(recipient_user)
内容的提问来源于stack exchange,提问作者Murcielago
相关产品推荐
相关产品推荐

