Продвинутый Django 5 для продолжающих

Прогресс по курсу:  0/193

8.7 Работа с WebSocket, добавление асинхронности
3 из 3 шагов пройдено

Следующим шагом является обработка этого сообщения в потребителе на серверной части.

Измените, GroupConsumer как показано ниже:

class GroupConsumer(AsyncWebsocketConsumer):
        ....
    async def receive(self, text_data=None, bytes_data=None):
        text_data = json.loads(text_data)
        type = text_data.get("type", None)
        message = text_data.get("message", None)
        author = text_data.get("author", None)
        if type == "text_message":
            user = await database_sync_to_async(User.objects.get)(email=author)
            message = await database_sync_to_async(Message.objects.create)(
            author = user,
            content = message,
            group = self.group
            )
        await self.channel_layer.group_send(self.group_uuid, {
            "type":"text_message",
            "message":str(message),
            "author":author
        })

    async def text_message(self, event):
        message = event["message"]
        author = event.get("author")
        
        returned_data = {
            "type":"text_message",
            "message":message,
            "group_uuid":self.group_uuid
        }
        await self.send(json.dumps(
                returned_data
                ))


Когда вы отправляете сообщение с помощью group_send метода класса channel_layers, оно вызывает метод класса-потребителя с тем же именем, что и значение ключа типа в сообщении. В этом методе вы можете отправить сообщение с помощью метода self.send().

В модели Group есть методы add_user_to_group и remove_user_from_group, которые вы использовали в методах join_group и leave_group потребителя JoinAndLeaveGroup. Эти методы создают объекты модели Event типа join и leave соответственно для пользователя.

Мы также можем добавить сигналы, чтобы отправить это сообщение о событии во внешний интерфейс, чтобы уведомить пользователей в группе, когда новый пользователь присоединился или вышел.


Создайте файл signals.py в директории приложения chat и добавьте в него следующий код:

from django.dispatch import receiver
from .models import Event
from django.db.models.signals import post_save
from channels.layers import get_channel_layer
from asgiref.sync import async_to_sync


@receiver(post_save, sender=Event)
def broadcast_event_to_groups(sender, instance, **kwargs):
    channel_layer = get_channel_layer()
    group_uuid = str(instance.group.uuid)
    event_message = str(instance)
    async_to_sync(channel_layer.group_send)(group_uuid,
                                            {
                                                "type": "text_message",
                                                "message": event_message,
                                                "status": instance.type,
                                                "user": str(instance.user)
                                            }
                                            )


Каждый потребительский класс имеет атрибут channel_layer, к которому мы можем получить доступ внутри потребителя как self.channel_layer. Однако, когда мы находимся вне потребительского класса, например в broadcast_event_to_groups, мы можем получить уровень канала только через функцию get_channel_layer().

Также нам необходимо зарегистрировать сигнал, для этого в файле chat/apps.py изменим код, добавив функцию ready()

from django.apps import AppConfig


class ChatConfig(AppConfig):
    default_auto_field = 'django.db.models.BigAutoField'
    name = 'chat'

# new
    def ready(self):
        import chat.signals

Будьте вежливы и соблюдайте наши принципы сообщества. Пожалуйста, не оставляйте решения и подсказки в комментариях, для этого есть отдельный форум.
Оставить комментарий

Не увидел информации, что при создании сигнала, необходимо добавить в apps.py в приложении chat следующий код:

from django.apps import AppConfig


class ChatConfig(AppConfig):
    default_auto_field = 'django.db.models.BigAutoField'
    name = 'chat'

    # New
    def ready(self):
        import chat.signalsЯ прав?

@Селянинов_Игорь, Абсолютно правы, когда писали чат, я специально отключил сигналы, чтобы на этапе тестирования не выводилась лишняя информация в чат и забыл. И еще, у нас в сигналах ошибка, там должен быть "type": "text_message", а не "type": "event_message"

Поправил лекцию, спасибо!