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

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

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

Группы слоев канала

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

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

Вам необходимо настроить channel_layers в файле settings.py через конфигурацию CHANNEL_LAYERS, прежде чем вы сможете его использовать.

Пакет channels_redis является единственным официально поддерживаемым канальным слоем, поддерживаемым для производственного использования (исходя из документации по Channels).

Но в целях разработки вы можете использовать уровень канала в памяти, который предоставляет пакет Django-channels.

Добавьте следующий код в файл настроек settings.py:

CHANNEL_LAYERS = {
    "default": {
        "BACKEND": "channels.layers.InMemoryChannelLayer"
    }
}


Добавьте следующее в файл chats/consumer.py

from channels.generic.websocket import WebsocketConsumer, AsyncWebsocketConsumer
from channels.layers import channel_layers
from channels.db import database_sync_to_async
import asyncio
            ....

class GroupConsumer(AsyncWebsocketConsumer):
    async def connect(self):
        self.group_uuid = str(self.scope["url_route"]["kwargs"]["uuid"])
        self.group = await database_sync_to_async(Group.objects.get)(uuid = self.group_uuid)
        await self.channel_layer.group_add(
                self.group_uuid,self.channel_name)
   
        self.user = self.scope["user"]
        await self.accept()

    async def receive(self, text_data=None, bytes_data=None):
        pass


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

Пакет Channels предоставляет также database_sync_to_async который может преобразовать операции в асинхронный тип.

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

Конечная точка веб-сокета, которая будет подключаться к этой группе, будет groups/<uuid:uuid>/

В методе connect мы извлекаем uuid из пути URL-адреса из атрибутов маршрута метаданных области. Мы получаем объект Group uuid с помощью асинхронного метода database_sync_to_async.

Уровень канала имеет методы send()group_send()group_add()group_discard() которые тоже являются асинхронными функциями.

Метод group_add добавляет экземпляр потребителя в группу. Метод group_send рассылает сообщения потребителям в той же группе.

await self.channel_layer.group_add(self.group_uuid,self.channel_name)

 Строка выше в методе connect добавляет экземпляр класса GroupConsumer, имя которого хранится в self.channel_name, в группу каналов, идентифицируемую с помощью uuid группового чата.


Далее нам необходимо создать шаблон URL-адреса веб-сокета для этого потребителя. Добавьте следующий код в файл chat/routing.py:

from django.urls import re_path, path

from . import consumers

websocket_urlpatterns = [
    path('', consumers.JoinAndLeave.as_asgi()),
    path('groups/<uuid:uuid>/', consumers.GroupConsumer.as_asgi())
]

 
Следующим шагом является добавление клиентского API веб-сокета на страницу chat/groupchat.html:

{%block script%}

<script>
        base_url = `${window.location.host}${window.location.pathname}`
        const chatSocket = new WebSocket(`ws://${base_url}`);

        chatSocket.onopen = function(e) {
        console.log("connected")
        };

        chatSocket.onclose = function (e) {
            console.error('Chat socket closed unexpectedly');
        };

        document.querySelector('#chat-message-input').focus();
        document.querySelector('#chat-message-input').onkeyup = function (e) {
            if (e.keyCode === 13) {  // enter, return
                document.querySelector('#chat-message-submit').click();
            }
        };

        document.querySelector('#chat-message-submit').onclick = function (e) {
            const messageInputDom = document.querySelector('#chat-message-input');
            const message = messageInputDom.value;
            chatSocket.send(JSON.stringify({
                'type': 'text_message',
                'author': `{{request.user}}`,
                'message': message
            }));
            messageInputDom.value = '';
        };
    </script>
{% endblock script %}

 
Когда пользователь вводит сообщение и нажимает кнопку отправки, сообщение отправляется на сервер с помощью метода chatSocket.send. Это отправляется вместе с именем, type = text_message также с автором, который является текущим пользователем в объекте request.


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