I'ved tried to setup Django with channels to provide notification to React.
https://github.com/axilaris/react-django-channels <-- I have put my project code here.
in backend/backend/settings.py
INSTALLED_APPS = [
..
'daphne',
'channels',
]
CHANNEL_LAYERS = {
'default': {
'BACKEND': 'channels.layers.InMemoryChannelLayer'
}
}
ASGI_APPLICATION = 'user_api.routing.application'
in backend/backend/asgi.py (I didnt touch anything)
import os
from django.core.asgi import get_asgi_application
from django.urls import path
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'backend.settings')
application = get_asgi_application()
in backend/user_api/routing.py
from channels.routing import ProtocolTypeRouter, URLRouter
from django.urls import path
from . import consumers
from django.core.asgi import get_asgi_application
django_asgi_app = get_asgi_application()
application = ProtocolTypeRouter({
"http": django_asgi_app,
"websocket": URLRouter([
path("ws/notifications/", consumers.NotificationConsumer.as_asgi()),
]),
})
in backend/user_api/consumers.py
from channels.generic.websocket import AsyncWebsocketConsumer
import json
class NotificationConsumer(AsyncWebsocketConsumer):
async def connect(self):
print("XXX connect")
await self.accept()
async def disconnect(self, close_code):
print("XXX disconnect")
pass
async def receive(self, text_data):
print("XXX receive")
text_data_json = json.loads(text_data)
message = text_data_json['message']
await self.send(text_data=json.dumps({
'message': message
}))
async def notification_message(self, event):
print("XXX notification_message")
await self.send(text_data=json.dumps(event["text"]))
Finally in React, App.js
useEffect(() => {
const ws = new WebSocket('ws://localhost:8000/ws/notification/');
ws.onopen = () => {
console.log('Connected to notification websocket');
};
ws.onmessage = e => {
const data = JSON.parse(e.data);
setMessage(data.message);
};
ws.onerror = e => {
console.error('WebSocket error', e);
};
ws.onclose = e => {
console.error('WebSocket closed', e);
};
return () => {
ws.close();
};
}, []);
In views.py (when press login submit, it should trigger a notification websocket to React)
class UserLogin(APIView):
permission_classes = (permissions.AllowAny,)
authentication_classes = (SessionAuthentication,)
##
def post(self, request):
print("YYY UserLogin")
logging.debug("XXX UserLogin")
channel_layer = get_channel_layer()
async_to_sync(channel_layer.group_send)(
'notifications',
{
'type': 'notification_message',
'text': 'test send',
}
)
return Response({"email": "[email protected]"}, status=status.HTTP_200_OK)
Note that React is running on port 3000 and Django is on port 8000
% npm start <-- React
% python manage.py runserver <-- Django
logs from django and react https://gist.github.com/axilaris/3e3498ae670514c45ba6a36d8511c797
react logs
App.js:79 WebSocket connection to 'ws://localhost:8000/ws/notifications/' failed: WebSocket is closed before the connection is established.
App.js:71 WebSocket error Event {isTrusted: true, type: 'error', target: WebSocket, currentTarget: WebSocket, eventPhase: 2, …}
App.js:75 WebSocket closed CloseEvent {isTrusted: true, wasClean: false, code: 1006, reason: '', type: 'close', …}
localhost/:1 Error while trying to use the following icon from the Manifest: http://localhost:3000/logo192.png (Download error or resource isn't a valid image)
App.js:62 Connected to notification websocket
django logs
System check identified 1 issue (0 silenced).
March 28, 2024 - 11:01:17
Django version 4.1.5, using settings 'backend.settings'
Starting ASGI/Daphne version 4.1.0 development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.
WebSocket HANDSHAKING /ws/notifications/ [127.0.0.1:57763]
INFO:django.channels.server:WebSocket HANDSHAKING /ws/notifications/ [127.0.0.1:57763]
WebSocket DISCONNECT /ws/notifications/ [127.0.0.1:57763]
INFO:django.channels.server:WebSocket DISCONNECT /ws/notifications/ [127.0.0.1:57763]
XXX connect
XXX disconnect
WebSocket HANDSHAKING /ws/notifications/ [127.0.0.1:57767]
INFO:django.channels.server:WebSocket HANDSHAKING /ws/notifications/ [127.0.0.1:57767]
XXX connect
WebSocket CONNECT /ws/notifications/ [127.0.0.1:57767]
INFO:django.channels.server:WebSocket CONNECT /ws/notifications/ [127.0.0.1:57767]
YYY UserView
HTTP GET /api/user 200 [0.02, 127.0.0.1:57761]
INFO:django.channels.server:HTTP GET /api/user 200 [0.02, 127.0.0.1:57761]
YYY UserView
HTTP GET /api/user 200 [0.00, 127.0.0.1:57761]
INFO:django.channels.server:HTTP GET /api/user 200 [0.00, 127.0.0.1:57761]
YYY UserLogout
HTTP POST /api/logout 200 [0.01, 127.0.0.1:57761]
INFO:django.channels.server:HTTP POST /api/logout 200 [0.01, 127.0.0.1:57761]
YYY UserLogin
HTTP POST /api/login 200 [0.00, 127.0.0.1:57761]
INFO:django.channels.server:HTTP POST /api/login 200 [0.00, 127.0.0.1:57761]
UPDATE: I think I got something working, like daphne is started up and there seems to a connection but aborted. pressing the login button should send the websocket notification but I dont see any message received in React side.
Reference 1
Problem :-
Look below.
It's
notifications.And
It's
notification.Path should be same path.
Use as below.
Answer :-
And
Reference 2
Info :-
1) If you have configured django-channels your console output opon
python manage.py runservershould be something like below.Look for
Starting ASGI/Daphne version x.x.x.2) Daphne is required in development server.
Look here
As I understand, you need to reconnect on error. App should be trying to connect always, if not connected already.
Like this.
Consumer should be able to refer specific users inside views.py. So, unique groups are required for every user. User must be added to their group upon connection accept.
Inside browser javascript code.
Consumer path.
Inside consumer.
in
views.py