Python Django: отправка сообщения с сервера клиенту при сохранении базы данных () - PullRequest
2 голосов
/ 07 октября 2019

Я хочу уведомить клиента, когда моя модель будет сохранена. Я начал с создания django-сигнала на post_save.

@receiver(post_save, sender=Scooter)
async def scooter_post_update(sender, instance, created, **kwargs):
    # Notify client here

Затем я создал класс AsyncConsumer из django-каналов и обеспечил его маршрутизацию.

// routing.py
    application = ProtocolTypeRouter({
        # Empty for now (http->django views is added by default)
        'websocket': AllowedHostsOriginValidator(
            AuthMiddlewareStack(
                URLRouter(
                    [
                        path('scooters/', ScootersUpdateConsumer)
                    ]
               )
        )
    )
})

// consumers.py
    class ScootersUpdateConsumer(AsyncConsumer):
        async def websocket_connect(self, event):
            print("Connected!", event)
            await self.send({
                "type": "websocket.accept"
            })
        async def send_message(self):
            await self.send({
                "type": "websocket.send",
                'text': 'Oy, mate!'
            })
        async def websocket_receive(self, event):
            print("Receive!", event)
        async def websocket_disconnect(self, event):
            print("Disconnected!", event)

Теперь мой вопрос: как можноЯ вызываю send_message () из метода scooter_post_update ().

1 Ответ

1 голос
/ 08 октября 2019

Шаги действительно просты. Вы должны получить канальный слой и просто отправить сообщение с ключом type, установленным в качестве имени метода прослушивания:

    import channels
    from asgiref.sync import async_to_sync

    @receiver(post_save, sender=Scooter)
    def scooter_post_update(sender, instance, created, **kwargs):
        channel_layer = channels.layers.get_channel_layer()
        async_to_sync(channel_layer.send)(
            {"type": "send_message", "data": data}
        )

и любым другим материалом, который вы хотите отправить по каналу.

Помните, что все передаваемые вами данные должны быть сериализуемыми, поэтому вам нужно заранее позаботиться о том, чтобы все ваши объекты были сериализованы.

Обязательная часть словаря, которую вы передаете в sendМетод - это ключ type (как упоминалось ранее), который должен содержать имя метода, который будет вызываться у потребителя.

Кроме того, вы можете использовать группы, чтобы вы могли передавать сообщение группепрослушивателей:

    import channels
    from asgiref.sync import async_to_sync

    @receiver(post_save, sender=Scooter)
    def scooter_post_update(sender, instance, created, **kwargs):
        channel_layer = channels.layers.get_channel_layer()
        async_to_sync(channel_layer.group_send)(
            "group_name", {"type": "send_message", "data": data}
        )

и на стороне потребителя:

    class ScootersUpdateConsumer(AsyncConsumer):
        async def websocket_connect(self, event):
            await self.channel_layer.group_add("group_name", self.channel_name)
            await self.send({
                "type": "websocket.accept"
            })

Обратите внимание, что в обоих случаях используется оболочка async_to_sync, которая должна использоваться при вызове асинхронного кода изобласть синхронизации.

...