Search code examples
pythondjangodjango-channels

How to send a message to all consumers using Django Channels 3.0.0?


I am trying to develop an interface that contains a section that shows all active users. So, when a user connects to the WebSocket I want to send data to all connected consumers.

Currently, I wrote a code that when the user connects it sends data to the connected user only. I want somehow to make the message be sent to all active users/consumers.

This is the path to my WebSocket handler/view

path('test_ws/', websocket.TestConsumer.as_asgi()),

And here is the handler

class NewsMentionConsumer(AsyncWebsocketConsumer):

groups = ["newsmention1"]
channel_name = 'news_mention'
active_users = []

async def connect(self):
    await self.channel_layer.group_add(self.groups[0], self.channel_name)
    await self.channel_layer.group_send(self.groups[0], {
        'type': 'send_updates',
        'text': json.dumps({
            'id': self.scope['user'].id,
            'username': self.scope['user'].username,
            'active_users': self.active_users
        })
    })
    await self.accept()
    self.active_users.append(self.scope['user'])

async def send_updates(self, event):
    # TODO: Make this send to all users/consumers
    await self.send(event["text"])

I am facing a problem understanding the examples in django.channels docs and tried using send_group function but it doesn't really work. Any suggestions?

EDIT: add all users to the same group with unique names.

async def connect(self):
    await self.channel_layer.group_add(self.groups[0], self.unique_name());
    await self.channel_layer.group_send(self.groups[0], { ... });

group_send still sends the message to the requested user only.

EDIT 2: after adding the init function.

Now, I have a channel_name but I am getting a new error when I am trying to send the data to all consumers in the group:

class NewsMentionConsumer(AsyncWebsocketConsumer):

group = "newsmention1"
active_users = []

def __init__(self, *args, **kwargs):
    super().__init__(*args, **kwargs)

async def connect(self):
    await self.channel_layer.group_add(
        self.group,
        self.channel_name,
    )

    await self.channel_layer.group_send(self.group, {
        'type': 'send_updates',
        'id': self.scope['user'].id,
        'username': self.scope['user'].username,
        'some_data_to_all_clients': some_data_to_all_clients()
    })

async def disconnect(self, close_code):
    await self.channel_layer.group_discard(self.group, self.channel_name)

async def send_updates(self, event):
    await self.channel_layer.send_group(self.group, event)


'RedisChannelLayer' object has no attribute 'send_group'

Any suggestions?

EDIT 3:

    async def connect(self):
        await self.accept()
        await self.channel_layer.group_add(
            self.group,
            self.channel_name,
        )
        self.active_users.append({
            'id': self.scope['user'].id,
            'username': self.scope['user'].username
        })
        await self.channel_layer.group_send(self.group, {
            'type': 'send_updates',
            'id': self.scope['user'].id,
            'username': self.scope['user'].username,
            'some_data_to_all_clients': some_data_to_all_clients()
        })

    async def send_updates(self, event):
        await self.send(json.dumps(event))

Solution

  • This is a bug of Django Channels 3.0.0. It was fixed in 3.0.1.