Как я пытался подружить Django и Websockets

Моя цель - предложение широкого ассортимента товаров и услуг на постоянно высоком качестве обслуживания по самым выгодным ценам.

Когда браузер клиенту нужно постоянное обновление данных с сервера, на ум сразу приходят сокеты. Но после множества просмотренных мной гайдов по данной теме, я не нашел ничего одновременно и актуального, и с нормальными объяснениями ну или хотя бы работающего. В итоге просидев пару-тройку часов у меня получилось собрать пазл из миллиона статей с Хабра и пары видеороликов от моих коллег из Индии.

Установка

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

Python

pip install channels

pip install channels-redis

pip install daphne

Если при установке daphne пип выдает ошибку про C++, то скачиваем BuildTools и во время установки выбираем "Разработка классических приложений на C++". Ребутаем комп и снова запускаем pip install.

Шаг №1

В файл settings.py добавляем загруженные пакеты(Причем исходя из документации - daphne надо добавить обязательно в начало списка):

INSTALLED_APPS = [
  'daphne',
  'channels',
  ...
]

В этом же файле изменяем:

WSGI_APPLICATION = 'yourapp.wsgi.application'

на:

ASGI_APPLICATION = 'yourapp.asgi.application'

Добавляем данные Channel layers в settings.py, конфигурация зависит от того, где у вас стоит Redis, подробнее тут. Для тестов я использовал такой сетап:

CHANNELS_LAYERS = {
  'default': {
    'BACKEND': 'channels.layers.InMemoryChannelLayer'
  }
}

Шаг №2

Создаем файл consumers.py в директории нашего приложения. Если вы работали с Class Based Views в Django то Consumers вам покажется знакомым.

Создаем свой обработчик:

from channels.consumer import AsyncConsumer


YourConsumer(AsyncConsumer):

    async def websocket_connect(self, event):
        await self.send({"type": "websocket.accept"})

    async def websocket_recieve(self, text_data):
        await self.send({
            "type": "websocket.send",
            "text": "Hello from Django socket"
        })

    async def websocket_disconnect(self, event):
        pass

Каждый метод класса YourConsumer отвечает за свой тип запросов через сокеты. Очень похоже на CBV

Шаг №3

Изменяем данные файла asgi.py в корневой директории проекта:

from channels.auth import AuthMiddlewareStack
from channels.routing import ProtocolTypeRouter
from channels.routing import URLRouter

from django.core.asgi import get_asgi_application
from django.urls import path


import os
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'yourapp.settings')


from yourapp.consumers import YourConsumer


django_asgi_app = get_asgi_application()

application = ProtocolTypeRouter({
    'http': django_asgi_app,
    'websocket': AuthMiddlewareStack(
        URLRouter([
            path('ws', YourConsumer.as_asgi())
        ])
    )
})

В URLRouter мы прописываем путь, по которому будет доступен Consumer. Например в данном случае для 127.0.0.1 это - ws://127.0.0.1:8000/ws. Это очень похоже на концепцию urls.py, кстати при желании можно вынести все пути в отдельный файл routers.py и импортировать их потом в корневую директорию.

Тестируем

Запускаем локалку и отправляем запросы к сокету. Например через Js:

const socket = new WebSocket('ws://127.0.0.1:8000/ws');

socket.onopen = function(e) {
  socket.send(JSON.stringify({
    message: 'Hello from Js client'
  }));
};

socket.onmessage = function(event) {
  try {
    console.log(event);
  } catch (e) {
    console.log('Error:', e.message);
  }
};
Запускаем запрос и видим ответ который мы прописывали в consumers.py
Запускаем запрос и видим ответ который мы прописывали в consumers.py

Ссылки

Документация

Гитхаб

Мой тг

Источник: https://habr.com/ru/post/700100/


Интересные статьи

Интересные статьи

Когда мы взялись за гибридный проект, в котором одновременно использовались Django и React, мы столкнулись с дилеммой: как интегрировать две эти части, в особенности, как разрешить шаблонам Django ото...
Идея появилась из проблемы. Проблема появилась из негодования. Мне было жутко неприятно от мысли, что при повороте экрана приходится проделывать серьезную работу над тем,...
Вообще Postgres очень известен и о расширении ltree написано, если немного, то достаточное кол-во публикаций, в том числе и на хабре тоже, да и сообщество Laravel довольн...
В небольших по размеру организациях как правило не больше одной установки Jira, Servicedesk и Confluence, которыми пользуются все, начиная от охранника и заканчивая QA. Как сделать так, чтобы и в...
На сегодняшний день у сервиса «Битрикс24» нет сотен гигабит трафика, нет огромного парка серверов (хотя и существующих, конечно, немало). Но для многих клиентов он является основным инструментом ...