You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何在Django channels 2.x中获取所有已创建房间的列表?

当然可以实现啦!不过Django Channels 2.x本身确实没有内置的方法直接返回所有已创建房间的列表,不过我们可以通过几种自定义方案来搞定这个需求,下面给你详细说说常用的几种思路:

方案1:用缓存跟踪活跃房间

这种方式适合轻量场景,不需要持久化房间信息,只需要跟踪当前活跃的房间:

  • 当用户连接到房间时,把房间ID/名称存入缓存的集合中
  • 当房间最后一个用户断开连接时,将房间从缓存中移除
  • 示例代码:
from django.core.cache import cache
from asgiref.sync import sync_to_async

async def connect(self):
    room_name = self.scope['url_route']['kwargs']['room_name']
    await self.channel_layer.group_add(
        room_name,
        self.channel_name
    )
    # 将房间名加入缓存集合
    await sync_to_async(cache.sadd)('active_rooms', room_name)
    # 维护房间在线用户计数
    await sync_to_async(cache.incr)(f'room_{room_name}_users', 1)
    await self.accept()

async def disconnect(self, close_code):
    room_name = self.scope['url_route']['kwargs']['room_name']
    await self.channel_layer.group_discard(
        room_name,
        self.channel_name
    )
    # 减少在线用户计数
    user_count = await sync_to_async(cache.incr)(f'room_{room_name}_users', -1)
    # 如果计数<=0,移除房间并删除计数键
    if user_count <= 0:
        await sync_to_async(cache.srem)('active_rooms', room_name)
        await sync_to_async(cache.delete)(f'room_{room_name}_users')
  • 获取房间列表的代码:
from django.core.cache import cache
from asgiref.sync import sync_to_async

async def get_active_rooms():
    # 从缓存中获取所有活跃房间
    rooms = await sync_to_async(cache.smembers)('active_rooms')
    # 转换为字符串列表(如果需要的话)
    return [room.decode() if isinstance(room, bytes) else room for room in rooms]
方案2:用数据库模型存储房间信息

如果需要持久化房间的详细信息(比如创建时间、描述等),或者需要更稳定的房间管理,推荐用数据库模型:

  • 首先定义一个Room模型:
from django.db import models

class Room(models.Model):
    name = models.CharField(max_length=255, unique=True, verbose_name="房间名称")
    is_active = models.BooleanField(default=True, verbose_name="是否活跃")
    online_users = models.IntegerField(default=0, verbose_name="在线用户数")
    created_at = models.DateTimeField(auto_now_add=True, verbose_name="创建时间")

    class Meta:
        verbose_name = "房间"
        verbose_name_plural = "房间"
  • 在消费者中更新房间状态:
from asgiref.sync import sync_to_async
from .models import Room

async def connect(self):
    room_name = self.scope['url_route']['kwargs']['room_name']
    # 获取或创建房间
    room, created = await sync_to_async(Room.objects.get_or_create)(name=room_name)
    # 更新在线用户数
    room.online_users += 1
    room.is_active = True
    await sync_to_async(room.save)()
    
    await self.channel_layer.group_add(room_name, self.channel_name)
    await self.accept()

async def disconnect(self, close_code):
    room_name = self.scope['url_route']['kwargs']['room_name']
    await self.channel_layer.group_discard(room_name, self.channel_name)
    
    # 更新在线用户数
    try:
        room = await sync_to_async(Room.objects.get)(name=room_name)
        room.online_users -= 1
        if room.online_users <= 0:
            room.is_active = False
        await sync_to_async(room.save)()
    except Room.DoesNotExist:
        pass
  • 获取所有房间列表的代码:
from asgiref.sync import sync_to_async
from .models import Room

async def get_all_rooms():
    # 获取所有活跃房间,也可以去掉filter获取全部
    rooms = await sync_to_async(list)(
        Room.objects.filter(is_active=True).values_list('name', flat=True)
    )
    return rooms
方案3:直接从Channel Layer后端查询(局限性较大)

如果你的Channel Layer用的是Redis后端,可以直接查询Redis中存储的组信息,但这种方法耦合了具体的后端实现,通用性不强:

  • 示例代码(使用Redis客户端):
import redis
from asgiref.sync import sync_to_async

async def get_redis_rooms():
    # 初始化Redis客户端,根据你的配置修改参数
    r = redis.Redis(host='localhost', port=6379, db=0)
    # Channels的组键格式通常是"asgi:group:房间名称"
    room_keys = await sync_to_async(r.keys)('asgi:group:*')
    # 提取房间名称
    rooms = [key.decode().split(':')[-1] for key in room_keys]
    return rooms

注意: 这种方法不需要额外维护数据,但如果你的Channel Layer配置了键前缀,或者换用了其他后端(比如内存版),这个方法就会失效,只适合特定场景。


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

火山引擎 最新活动