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

如何获取Django Websocket已登录用户的成员列表?

解决方案:获取Django Websocket群组的已登录用户列表

Django Channels 的 Channel Layer 本身没有内置方法直接获取群组成员列表,因此需要自行维护群组的成员信息。最适合实时场景的方案是用 Redis 存储成员数据(因为 Channel Layer 通常也用 Redis 做后端,兼容性好),以下是具体实现步骤:

1. 准备工作

  • 确保已安装 Redis 并启动服务
  • 安装 Redis Python 客户端:pip install redis
  • 确保 Django Channels 已配置 Redis 作为 Channel Layer 后端(在 settings.py 中):
CHANNEL_LAYERS = {
    "default": {
        "BACKEND": "channels_redis.core.RedisChannelLayer",
        "CONFIG": {
            "hosts": [("127.0.0.1", 6379)],
        },
    },
}

2. 修改 ChatConsumer 实现成员管理

import json
import redis
from channels.generic.websocket import AsyncWebsocketConsumer

# 初始化 Redis 客户端,根据你的 Redis 配置调整参数
redis_client = redis.Redis(host='localhost', port=6379, db=0)

class ChatConsumer(AsyncWebsocketConsumer):
    async def connect(self):
        self.room_group_name = self.scope["url_route"]["kwargs"]["room_name"]
        self.user = self.scope['user']

        # 拒绝未登录用户连接
        if not self.user.is_authenticated:
            await self.close()
            return

        # 将当前客户端加入 Channel Layer 群组
        await self.channel_layer.group_add(
            self.room_group_name,
            self.channel_name
        )

        # 将用户信息存入 Redis 集合(用 username 作为唯一标识)
        redis_key = f"room_members:{self.room_group_name}"
        redis_client.sadd(redis_key, self.user.username)

        # 获取当前群组的所有成员,转换为字符串列表
        member_list = [member.decode('utf-8') for member in redis_client.smembers(redis_key)]

        await self.accept()
        # 向当前客户端发送初始成员列表
        await self.send(text_data=json.dumps({
            'channel_name': self.channel_name,
            'room_group_name': self.room_group_name,
            'member_list': member_list
        }))

        # 通知群组内其他用户更新成员列表
        await self.channel_layer.group_send(
            self.room_group_name,
            {
                'type': 'broadcast_member_list',
                'member_list': member_list
            }
        )

    async def disconnect(self, close_code):
        # 从 Channel Layer 群组移除当前客户端
        await self.channel_layer.group_discard(
            self.room_group_name,
            self.channel_name
        )

        # 已登录用户断开时,从 Redis 移除其信息
        if self.user.is_authenticated:
            redis_key = f"room_members:{self.room_group_name}"
            redis_client.srem(redis_key, self.user.username)
            # 获取更新后的成员列表
            updated_members = [member.decode('utf-8') for member in redis_client.smembers(redis_key)]
            # 通知其他用户成员列表更新
            await self.channel_layer.group_send(
                self.room_group_name,
                {
                    'type': 'broadcast_member_list',
                    'member_list': updated_members
                }
            )

    # 处理群组内的成员列表广播消息
    async def broadcast_member_list(self, event):
        await self.send(text_data=json.dumps({
            'type': 'member_list_updated',
            'member_list': event['member_list']
        }))

3. 关键逻辑说明

  • 成员存储:用 Redis 集合存储每个群组的成员,集合的键格式为 room_members:{群组名},值为用户的 username(也可以用 user_id 更稳定)。
  • 连接时处理:用户连接成功后,将其加入 Redis 集合,然后获取完整成员列表返回给当前客户端,并广播给群组内所有用户。
  • 断开时处理:用户断开连接后,从 Redis 集合中移除其信息,再次广播更新后的成员列表,确保所有客户端的列表都是最新的。
  • 认证校验:通过 self.scope['user'] 获取登录用户,拒绝未认证用户连接,避免匿名用户混入。

4. 可选优化

  • 如果需要存储更多用户信息(如头像、在线状态),可以用 Redis 哈希表代替集合,键为用户 ID,值为用户信息的 JSON 字符串。
  • 若需重启服务后保留成员数据,可开启 Redis 的持久化功能,或者结合数据库做持久化备份。
  • 对于匿名用户,可以生成唯一的会话 ID(如 self.scope['session'].session_key)作为标识存入 Redis。

内容的提问来源于stack exchange,提问作者whitebear

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 02:24:51