You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.04 02:05:18