Потребитель каналов Django не получает данные

Я пытаюсь написать потребителя websocket, который получает все непрочитанные уведомления, а также все уведомления, которые создаются, пока клиент все еще подключен к websocket.

Я могу подключиться к потребителю, и он показывает мне все активные уведомления. Проблема в том, что он не показывает мне новые уведомления, когда они создаются и отправляются из метода сохранения модели.

consumers.py

class NotificationConsumer(WebsocketConsumer):
    def get_notifications(self, user):
        new_followers = NotificationSerializer(Notification.objects.filter(content=1), many=True)

        notifs = {
            "new_followers": new_followers.data
        }

        return {
            "count": sum(len(notif) for notif in notifs.values()),
            "notifs": notifs
        }

    def connect(self):
        user = self.scope["user"]

        if user:
            self.channel_name = user.username
            self.room_group_name = 'notification_%s' % self.channel_name

            notification = self.get_notifications(self.scope["user"])
            print("Notification", notification)

            self.accept()
            return self.send(text_data=json.dumps(notification))
        
        self.disconnect(401)
    
    async def disconnect(self, close_code):
        await self.channel_layer.group_discard(
            self.room_group_name,
            self.channel_name
        )
    
    async def receive(self, text_data):
        text_data_json = json.loads(text_data)
        count = text_data_json['count']
        notification_type = text_data_json['notification_type']
        notification = text_data_json['notification']
        print(text_data_json)

        await self.channel_layer.group_send(
            self.room_group_name,
            {
                "type": "receive",
                "count": count,
                "notification_type": notification_type,
                "notification": notification
            }
        )

models.py

class Notification(models.Model):
    content = models.CharField(max_length=200, choices=NOTIFICATION_CHOICES, default=1)
    additional_info = models.CharField(max_length=100, blank=True)
    seen = models.BooleanField(default=False)
    users_notified = models.ManyToManyField("core.User", blank=True)
    user_signaling = models.ForeignKey("core.User", on_delete=models.CASCADE, related_name="user_signaling")

    def save(self, *args, **kwargs):
        if self._state.adding:
            super(Notification, self).save(*args, **kwargs)

        else:
            notif = Notification.objects.filter(seen=False)
            data = {
                "type": "receive",
                "count": len(notif),
                "notification_type": self.content,
                "notification": self.additional_info
            }

            channel_layer = get_channel_layer()
            for user in self.users_notified.all():
                async_to_sync(channel_layer.group_send(
                        f"notification_{user.username}",
                        data
                    )
                )
                print(channel_layer)

Я проверяю наличие self._state.adding, поэтому он будет посылать сообщение websocket только тогда, когда users_notified уже были добавлены после создания модели.

пример использования:

notif = Notification.objects.create(
      content=1, 
      user_signaling=user,
      additional_info=f"{user.username} just followed you!"
)
notif.users_notified.add(other_user)
notif.save()

Обычно я использую сигналы, в вашем случае вы могли бы использовать сигнал post_save вместо переопределения модели save().

channel_layer = get_channel_layer()


@receiver(post_save, sender=Notification)
def notification_on_create(sender, instance, created, **kwargs) -> None:
    _, _ = sender, kwargs
    if created:
        return None
    notif = Notification.objects.filter(seen=False)
    data = {
                "type": "receive",
                "count": len(notif),
                "notification_type": instance.content,
                "notification": instance.additional_info
            }
    for user in self.users_notified.all():
        async_to_sync(channel_layer.group_send(
                f"notification_{user.username}", data))

Вернуться на верх