Я в проде запускал отдельный экземпляр приложения для 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)
// тут делаем что-то с данными
})