Ответы пользователя по тегу Django Rest Framework
  • Как сделать вебсокеты в drf-проекте с реакт-фронтендом?

    @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)
            // тут делаем что-то с данными
         })
    Ответ написан
    Комментировать