DEV Community

Danil Poletavkin
Danil Poletavkin

Posted on

Django. Работа через WebSocket. Библиотека Channels

Ссылка на документацию https://channels.readthedocs.io/

Ссылка на проект github https://github.com/django/channels

Библиотека позволяет выполнять соединение с клиентской стороной как через http, так и через websocket. Подключая библиотеку к Django соединения будут выполняться через сервер-стандарт asgi, так как библиотека переопределит стандартное поведение Django. В остальном же функциональность остаётся та же самая, как обычно, через http можно вызывать контроллеры из файла views.py.

Классы-Потребители (Consumers)

Это специальный класс — потребитель сообщений. Принято располагать эти классы в модуле consumers.py.

Эти классы обрабатывают сообщения по протоколам отличным от http, например для работы с websocket класс создаётся следующим образом:

from channels.generic.websocket import WebsocketConsumer

class SimpleWsConsumer(WebsocketConsumer):
    pass
Enter fullscreen mode Exit fullscreen mode

В отличие от стандартной конфигурации при работе через http, когда маршруты располагаются в модуле urls.py при работе через websocket маршруты принято располагать в модуле routing.py

from django.urls import re_path
from . import consumers

websocket_urlpatterns=[
    re_path(r’ws/chat/(?P<room_name>\w+)/$’, consumers.SimpleWsConsumer.as_asgi()),
]
Enter fullscreen mode Exit fullscreen mode

Как видим, у класса-контроллера вместо обычного вызова as_view() вызывается метод as_asgi(), в остальном модуль маршрутов похож на стандартный urls.py

Подключаются же такие маршруты в модуле asgi.py

import os

from channels.auth import AuthMiddlewareStack
from channels.routing import ProtocolTypeRouter, URLRouter
from channels.security.websocket import AllowedHostsOriginValidator
from django.core.asgi import get_asgi_application
from chat import routing # Импортируется модуль routing.py, где как раз и настроены маршруты websocket

os.environ.setdefault('DJANGO_SETTINGS_MODULE','mysite.settings')
application=ProtocolTypeRouter({
    "http":get_asgi_application(),
    "websocket":AllowedHostsOriginValidator(AuthMiddlewareStack(URLRouter(routing.websockets_urlpatterns)) # Передаётся список маршрутов из модуля routing.py)
})
Enter fullscreen mode Exit fullscreen mode

Подключение коммуникационной системы потребителей. Слой Каналов (Channel layer)

Канал — это как путь, через который направляются сообщения. Для каждой вкладки веб-обозревателя создаётся свой канал. Каждому потребителю по умолчанию назначается уникальное имя канала channel_name, то есть если создать 10 вкладок (или приложение используют 10 разных пользователей), то будет создано 10 каналов. Наверное можно думать о канале как о канале соединения websocket. Каналы могут объединяться в группы, и тогда каналы, принадлежащие одной группе могут общаться между собой

Группа — это группа связанных каланов. Имея имя группы можно отправлять сообщения через все каналы этой группы. И, насколько понимаю, для каждого потребителя создаётся свой собственный канал с уникальным именем. Получается, что каналы объединяются в группы вместе со своими потребителями.

То есть можно сказать, что канал — это путь к потребителю, по которому идут сообщения, а потребитель — конечная точка для этих сообщений. Потребитель может принять сообщение, обработать его и отправить ответ.

Коммуникационная система работает через redis — нужно запустить redis и добавить пакет channels_redis

pip install channels_redis

И в модуле настроек settings.py коммуникационную систему нужно сконфигурировать

ASGI_APPLICATION='mysite.asgi.application'

CHANNEL_LAYERS={
    'default':{
        'BACKEND':'channels_redis.core.RedisChannelLayer',
        'CONFIG':{
            'hosts':[
                ('127.0.0.1',6379)
            ]
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

Добавление потребителя в группу

Потребителя можно добавить в группу методом channel_layer.group_add

import json

from asgiref.sync import async_to_sync
from channels.generic.websocket import WebsocketConsumer

class SimpleWsConsumer(WebsocketConsumer):
    def connect(self):
        self.room_name=self.scope['url_route'][^1]['kwargs']['room_name']
        self.room_group_name='chat_%s' % self.room_name
        # Добавление потребителя в группу
        async_to_sync(self.channel_layer.group_add)[^2](
            self.room_group_name, self.channel_name # Параметры метода channel_layer.group_add
        )
    self.accept() # Принять соединение

Enter fullscreen mode Exit fullscreen mode

Heroku

Simplify your DevOps and maximize your time.

Since 2007, Heroku has been the go-to platform for developers as it monitors uptime, performance, and infrastructure concerns, allowing you to focus on writing code.

Learn More

Top comments (0)

Image of Docusign

🛠️ Bring your solution into Docusign. Reach over 1.6M customers.

Docusign is now extensible. Overcome challenges with disconnected products and inaccessible data by bringing your solutions into Docusign and publishing to 1.6M customers in the App Center.

Learn more