I’ve gone through this tutorial twice:
And I’ve gone through the official docs of Django Channels at least enough to get started. Now granted the basic exampled did work on the docs. However, the enhanced version with rooms and online user list from the above-mentioned article is not working.
When the channel consumer calls user = self.scope['user']
it does grab something, however the username is always None (null).
I have the authentication middleware in use:
core/asgi.py
import os
from channels.auth import AuthMiddlewareStack # new import
from channels.routing import ProtocolTypeRouter, URLRouter
from django.core.asgi import get_asgi_application
import chat.routing
os.environ.setdefault(‘DJANGO_SETTINGS_MODULE’, ‘core.settings’)
application = ProtocolTypeRouter({
'http': get_asgi_application(),
'websocket': AuthMiddlewareStack( # new
URLRouter(
chat.routing.websocket_urlpatterns
)
), # new
})
I have the following Consumer code:
import json
from asgiref.sync import async_to_sync
from channels.generic.websocket import WebsocketConsumer
from .models import Room, Message
class ChatConsumer(WebsocketConsumer):
def __init__(self, *args, **kwargs):
super().__init__(args, kwargs)
self.room_name = None
self.room_group_name = None
self.room = None
self.user = None
self.user_inbox = None
def connect(self):
self.room_name = self.scope['url_route']['kwargs']['room_name']
self.room_group_name = f'chat_{self.room_name}'
self.room = Room.objects.get(name=self.room_name)
self.user = self.scope['user']
self.user_inbox = f'inbox_{self.user.username}'
# connection has to be accepted
self.accept()
# join the room group
async_to_sync(self.channel_layer.group_add)(
self.room_group_name,
self.channel_name,
)
users = [user.username for user in self.room.online.all()]
# send the user list to the newly joined user
self.send(json.dumps({
'type': 'user_list',
'users': users,
}))
if self.user.is_authenticated:
# create a user inbox for private messages
async_to_sync(self.channel_layer.group_add)(
self.user_inbox,
self.channel_name,
)
# send the join event to the room
async_to_sync(self.channel_layer.group_send)(
self.room_group_name,
{
'type': 'user_join',
'user': self.user.username,
}
)
self.room.online.add(self.user)
def disconnect(self, close_code):
async_to_sync(self.channel_layer.group_discard)(
self.room_group_name,
self.channel_name,
)
if self.user.is_authenticated:
# delete the user inbox for private messages
async_to_sync(self.channel_layer.group_add)(
self.user_inbox,
self.channel_name,
)
# send the leave event to the room
async_to_sync(self.channel_layer.group_send)(
self.room_group_name,
{
'type': 'user_leave',
'user': self.user.username,
}
)
self.room.online.remove(self.user)
def receive(self, text_data=None, bytes_data=None):
text_data_json = json.loads(text_data)
message = text_data_json['message']
if not self.user.is_authenticated:
return
if message.startswith('/pm '):
split = message.split(' ', 2)
target = split[1]
target_msg = split[2]
# send private message to the target
async_to_sync(self.channel_layer.group_send)(
f'inbox_{target}',
{
'type': 'private_message',
'user': self.user.username,
'message': target_msg,
}
)
# send private message delivered to the user
self.send(json.dumps({
'type': 'private_message_delivered',
'target': target,
'message': target_msg,
}))
return
# send chat message event to the room
async_to_sync(self.channel_layer.group_send)(
self.room_group_name,
{
'type': 'chat_message',
'user': self.user.username,
'message': message,
}
)
Message.objects.create(user=self.user, room=self.room, content=message)
def chat_message(self, event):
self.send(text_data=json.dumps(event))
def user_join(self, event):
self.send(text_data=json.dumps(event))
def user_leave(self, event):
self.send(text_data=json.dumps(event))
def private_message(self, event):
self.send(text_data=json.dumps(event))
def private_message_delivered(self, event):
self.send(text_data=json.dumps(event))
And my Authentication backends look like this:
AUTHENTICATION_BACKENDS = (
"social_core.backends.github.GithubOAuth2",
"social_core.backends.twitter.TwitterOAuth",
"social_core.backends.facebook.FacebookOAuth2",
"social_core.backends.linkedin.LinkedinOAuth2",
"social_core.backends.google.GoogleOAuth2",
"graphql_jwt.backends.JSONWebTokenBackend",
"django.contrib.auth.backends.ModelBackend",
)
I’m currently thinking maybe User.username is null and I should use email. Checking that now.