Задать вопрос
@Dbtzhv

Как сделать вебсокеты в drf-проекте с реакт-фронтендом?

Всем привет! Как работать с вебсокетами в разделённом (бэк/фронт) проекте?

В фул джанго проекте делал так (1-й ответ):
https://stackoverflow.com/questions/56913676/dynam...

Сейчас отдельно фронт на реакте и drf-бэк. Во фронте будет использоваться socketio. Как, в таком случае, правильно реализовать вебсокеты в drf-ке? Те же channels?

Думал, что можно как в ответе на стэке, просто js-часть будет делать теперь фронт на реакте, а не я в джанго-шаблонах. Но фронт сказал, что эндпоинты не нужны, чисто по событиям:
у него будет что-то типа soket.on("getTasks")
soket.on("addTask", task: {"новая задача"}
И я понятия не имею, как с этим работать
  • Вопрос задан
  • 99 просмотров
Подписаться 1 Простой Комментировать
Решения вопроса 1
@mewmew
Я в проде запускал отдельный экземпляр приложения для web socket. Channels отлично справляется со своей задачей. Документация отлично описана, да и много гайдов есть.
Как пример:
asgi.py
import os

from django.core.asgi import get_asgi_application
from channels.routing import ProtocolTypeRouter, URLRouter
from channels.security.websocket import AllowedHostsOriginValidator


os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'backend.settings')
get_asgi_app = get_asgi_application()

from notification import routing

application = ProtocolTypeRouter({
    "http": get_asgi_app,
    "websocket": AllowedHostsOriginValidator(
        URLRouter(
            routing.websocket_urlpatterns
        )
    ),
})


routing.py
from django.urls import path
from . import consumers

websocket_urlpatterns = [
    path(r'wss/notification/<str:room_name>/', consumers.NotificationConsumer.as_asgi()),
]


consumers.py
import json

from channels.generic.websocket import AsyncWebsocketConsumer

from service.auth.auth import get_auth


class NotificationConsumer(AsyncWebsocketConsumer):
    user = None

    async def connect(self):
        user = await get_auth(self.scope.get('query_string'))
        self.room_name = self.scope['url_route']['kwargs']['room_name']
        max_connections_allowed = 1
        user_connections_key = f'user_connections_{user.id}'

        current_connections = self.scope.get(user_connections_key, 0)

        if current_connections >= max_connections_allowed:
            await self.close()
        else:
            self.scope[user_connections_key] = current_connections + 1
            await self.channel_layer.group_add(
                self.room_name,
                self.channel_name
            )
            if user.is_access_allowed():
                self.user = user
                await self.accept()

    async def disconnect(self, close_code):
        pass

    async def receive(self, text_data):
        await self.send_notification({'message': text_data})

    async def send_notification(self, message):
        message = message["message"]
        await self.send(text_data=json.dumps({"message": message}))


def send_notification(username, message, type_notification, created_at, id_notification, options=None):
    channel_layer = get_channel_layer()
    async_to_sync(channel_layer.group_send)(
        f'notification-{username}',
        {'type': 'send.notification',
         'message': {'message': message, 'type_notification': type_notification, 'id': id_notification,
                     'created_at': created_at, 'notification_options': options}})


на фронте можно использовать нативные методы (образец из vue)
const socket = ref(null)
socket.value = new WebSocket(
      `ws://127.0.0.1:8000/wss/notification/notification-${user.username}/}`
    )
    socket.value.onopen = () => {
      console.log("otkrit")
    }
    socket.value.onclose = () => {
      console.log("zakrit")
    }

    socket.value.onerror = () => {
      console.log("error")
    }
    socket.value.onmessage = (message) => {
        const data = JSON.parse(message.data)
        // тут делаем что-то с данными
     })
Ответ написан
Комментировать
Пригласить эксперта
Ответы на вопрос 1
@Everything_is_bad
DRF это REST API, т.е. там архитектура построена на HTTP запросах, а в вебсокет их нет, получает что DRF тут боком и для вебсокетов он вообще не нужен. Правильно - вынести бизнес логику из DRF в отдельный слой, а в вебсокетах дергать только эту логику и ничего не знать про DRF

UPD: Так же такой вариант, если REST API уже реализован, то написать для вебсокетов отдельный прокси, лучше не на джанго, а на starlette (fastapp скорее тут будут излишен), aiohttp или другом async фреймворки, который умеет в вебсокет. Так вот, этот прокси и будет уже дергать эндпоинты твой DRF, реальными http запросам
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы