Как добавлять комнаты django channels?

Как на django channels создавать другие каналы, чтобы на их основе сделать личные сообщения пользователей? Я сделал все по гайду, но там только один канал, где может писать любой пользователь. Полагаю, нужно менять consumer.

    def connect(self):
        self.room_name = self.scope['url_route']['kwargs']['room_name']
        self.room_group_name = 'chat_%s' % self.room_name
        async_to_sync(self.channel_layer.group_add)(
            self.room_group_name,
            self.channel_name
        )
        self.accept()

Ответы (1 шт):

Автор решения: RoIVIan

Вы можете воспользоваться примером, на который ссылается документация Channels - https://github.com/andrewgodwin/channels-examples/tree/master/multichat

У каждого пользователя есть список доступных ему комнат. Нужно доработать модельки и метод get_room_or_error чтобы сообщения получали только те кто должен.

class ChatConsumer(AsyncJsonWebsocketConsumer):

    async def connect(self):
        self.rooms = set()

        if self.scope["user"].is_anonymous:
            await self.close()
        else:
            await self.accept()

            room_list = await get_room_list(self.scope["user"])
            for room in room_list:
                await self.channel_layer.group_add(
                    room.group_name,
                    self.channel_name,
                )

                self.rooms.add(room.id)
    
    async def receive_json(self, content):
        command = content.get("command", None)
            try:
                if command == "join":
                    await self.join_room(content["room"])
                ...
            
            except ClientError as e:
                await self.send_json({"error": e.code})


    async def join_room(self, room_id):
        room = await get_room_or_error(self.scope["user"], room_id)

        if settings.NOTIFY_USERS_ON_ENTER_OR_LEAVE_ROOMS:
            await self.channel_layer.group_send(
                room.group_name,
                {
                    "type": "chat.join",
                    "room_id": room_id,
                    "username": self.scope["user"].username,
                }
            )

        if room_id not in self.rooms:
            self.rooms.add(room_id)

            await self.channel_layer.group_add(
                room.group_name,
                self.channel_name,
            )

        await self.send_json({
            "join": str(room.id),
            "title": room.title,
        })

    async def chat_join(self, event):
        await self.send_json(
            {
                "msg_type": settings.MSG_TYPE_ENTER,
                "room": event["room_id"],
                "username": event["username"],
            },
        )

Моделька выглядит следующим образом:

class Room(models.Model):
    title = models.CharField(max_length=255)
    staff_only = models.BooleanField(default=False)

    def __str__(self):
        return self.title

    @property
    def group_name(self):
        return "room-%s" % self.id

Проверки на доступность комнаты для пользователя

@database_sync_to_async
def get_room_list(user):
    if not user.is_authenticated:
        raise ClientError("USER_HAS_TO_LOGIN")

    # для примера отфильтруем комнаты по staff_only
    room = Room.objects.filter(staff_only=user.is_staff)
    return room


@database_sync_to_async
def get_room_or_error(user, room_id):
    if not user.is_authenticated:
        raise ClientError("USER_HAS_TO_LOGIN")
    try:
        room = Room.objects.get(pk=room_id)
    except Room.DoesNotExist:
        raise ClientError("ROOM_INVALID")

    if room.staff_only and not user.is_staff:
        raise ClientError("ROOM_ACCESS_DENIED")
    return room
→ Ссылка