Click here to Skip to main content
15,904,024 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more: , +
I'm trying to establish a connection with my Django backend and Flutter code using WebSockets, but unfortunately I'm unable to do so, went through many articles and videos and everyone is basically doing the same without receiving an error.. Please give a little push to, I'm kinda new into this.

What I have tried:

First of all I created a new django app called 'chat_app' (added it into settings.py), where I created a new model of my Messages:

Python
class Message(models.Model):
        room = models.ForeignKey(Room, on_delete=models.CASCADE)
        sender = models.ForeignKey(User, on_delete=models.CASCADE)
        content = models.TextField()
        timestamp = models.DateTimeField(auto_now_add=True)
    
        def __str__(self):
            return self.content


Then I made my consumers.py (here I'm a little bit confused, isn't it better to refer to my room unique_id instead of name, since the ID is unique and not the name in my case? Decided to stick with the tutorial.)

Python
# chat/consumers.py

import json
from channels.generic.websocket import AsyncWebsocketConsumer
from asgiref.sync import sync_to_async
from .models import Message
from room_app.models import Room

class ChatConsumer(AsyncWebsocketConsumer):
    async def connect(self):
        self.unique_id = self.scope['url_route']['kwargs']['unique_id']
        self.room_group_name = 'chat_%s' % self.unique_id

        # Check if the room exists in the database
        if not await self.room_exists():
            await self.close()
            return

        # Join room group
        self.channel_layer.group_add(
            self.room_group_name,
            self.channel_name
        )

        self.accept()

    def disconnect(self, close_code):
        # Leave room group
        self.channel_layer.group_discard(
            self.room_group_name,
            self.channel_name
        )

    # Receive message from WebSocket
    def receive(self, text_data):
        text_data_json = json.loads(text_data)
        message = text_data_json['message']

        # Save message to database
        Message.objects.create(
            room=self.unique_id,
            user=self.scope['user'],
            content=message
        )

        # Send message to room group
        self.channel_layer.group_send(
            self.room_group_name,
            {
                'type': 'chat_message',
                'message': message,
                'username': self.scope['user'].username
            }
        )

    # Receive message from room group
    def chat_message(self, event):
        message = event['message']
        username = event['username']

        # Send message to WebSocket
        self.send(text_data=json.dumps({
            'message': message,
            'username': username
        }))
    
    @sync_to_async
    def room_exists(self):
        return Room.objects.filter(unique_id=self.unique_id).exists()


Done the routing.py

Python
# The WebSocket URL pattern for chat rooms is defined by this code
    websocket_urlpatterns = [
        re_path(r'ws/chat_app/(?P<room_name>\w+)/$', ChatConsumer.as_asgi()),
    ]


Then added it into my project URLs:

Python
urlpatterns = [
        path('admin/', admin.site.urls),
        ...,
        path('ws/', include(websocket_urlpatterns)),
    ]


And this is how I'm trying to establish a connection in Flutter, basically it is a new page, where I'm passing room data through the Navigator from the previous page:

class ChatScreen extends StatefulWidget {
  const ChatScreen({
    Key? key,
    required this.room,
  }) : super(key: key);
  final RoomModelResponse room;

  @override
  _ChatScreenState createState() => _ChatScreenState();
}

class _ChatScreenState extends State<ChatScreen> {
  final TextEditingController _controller = TextEditingController();
  final List<String> _messages = [];
  late WebSocketChannel _channel;

  @override
  void initState() {
    super.initState();
    _channel = IOWebSocketChannel.connect(
        'wss://192.168.0.11:8000/ws/chat_app/${widget.room.roomName}/'); // Update the WebSocket URL with your Django server address and room name
    _channel.stream.listen((message) {
      setState(() {
        _messages.add(message);
      });
    });
  }


Outputs:

In the flutter terminal I get the following message:
[ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: WebSocketChannelException: WebSocketChannelException: WebSocketException: Connection to 'http://192.168.0.11:8000/ws/chat_app/3wVCio/#' was not upgraded to websocket
#0      new IOWebSocketChannel._withoutSocket.<anonymous closure> (package:web_socket_channel/io.dart:119:24)
#1      Stream.handleError.<anonymous closure> (dart:async/stream.dart:931:16)
#2      _HandleErrorStream._handleError (dart:async/stream_pipe.dart:269:17)
#3      _ForwardingStreamSubscription._handleError (dart:async/stream_pipe.dart:157:13)
#4      _RootZone.runBinaryGuarded (dart:async/zone.dart:1606:10)
#5      _BufferingStreamSubscription._sendError.sendError (dart:async/stream_impl.dart:358:15)
#6      _BufferingStreamSubscription._sendError (dart:async/stream_impl.dart:376:7)
#7      _BufferingStreamSubscription._addError (dart:async/stream_impl.dart:280:7)
#8      _SyncStreamControllerDispatch._sendError (dart:async/stream_controller.dart:788:19)
#9 <…>


Django:
Not Found: /ws/chat_app/3wVCio/
[15/Feb/2024 16:46:19] "GET /ws/chat_app/3wVCio/ HTTP/1.1" 404 4379


Where the "3wVCio" is the unique_id of my room.

I will provide additional information if need

Update: The latest think I've tried is allowing all origin CORS in my project:
INSTALLED_APPS = [
    # other installed apps
    'corsheaders',
]
CORS_ALLOW_ALL_ORIGINS = True


Unfortunately, no success..
Posted
Comments
Richard Deeming 16-Feb-24 8:41am    
"allowing all origin CORS in my project"

Which project? The CORS headers need to be applied to the server that's being called; you can't change them in the client that's making the call.

Check your browser's developer console for any previous errors. If you have a CORS issue, it should show up there. Alternatively, check the browser's dev tools "network" tab to see if that gives you any clues.
gsemerdz 16-Feb-24 9:17am    
I just saw it as a solution in another thread for similar to my problem, however with or without the CORS configuration, the issue I have is the same
gsemerdz 16-Feb-24 10:34am    
"allowing all origin CORS in my project", I mean allowing it in my Django project, adding it in my Django settings.py

1 solution

You have basically answered your own question without knowing it -
Quote:
Then I made my consumers.py (here I'm a little bit confused, isn't it better to refer to my room unique_id instead of name, since the ID is unique and not the name in my case? Decided to stick with the tutorial.)


It seems you are using 'unique_id' in Django, but in Flutter, you are using 'roomName'. Make sure that you are using the correct parameter names throughout your modules. Update your Django 'ChatConsumer' to use 'room_name' instead of 'unique_id' -
Python
self.unique_id = self.scope['url_route']['kwargs']['room_name']
self.room_group_name = 'chat_%s' % self.unique_id

Make sure you update this throughout all of your your Django code.

Then make sure the WebSocket URL in your Flutter code is using the correct scheme ('ws or wss') based on your Django server configuration. If your Django server is using 'ws', you should use -
Dart
_channel = IOWebSocketChannel.connect(
    'ws://192.168.0.11:8000/ws/chat_app/${widget.room.roomName}/');

However, if your Django server is configured for secure WebSocket ('wss'), use -
Dart
_channel = IOWebSocketChannel.connect(
    'wss://192.168.0.11:8000/ws/chat_app/${widget.room.roomName}/');


The above should solve the errors.
 
Share this answer
 
Comments
gsemerdz 17-Feb-24 10:46am    
The Django server runs only on HTTP, because if I try to run it on 'wss', the following error appears 'code 400, message Bad request version ('À\x13À')
You're accessing the development server over HTTPS, but it only supports HTTP.'. Anyways, I have changed the code in flutter to be passing the room name as you suggest, again I'm getting the not found error: ""GET /ws/chat_app/testUser's%20room/ HTTP/1.1" 404 4423". Then I tried with keeping the same code in django as the one in the actual question, but instead in Flutter, I have provided the 'room.uniqueID'. Again without success - '"GET /ws/chat_app/3wVCio/ HTTP/1.1" 404 4379'
Andre Oosthuizen 17-Feb-24 12:25pm    
It looks like the room name you are passing from Flutter contains special characters. certain characters, like spaces and apostrophes, may need to be properly encoded. You should 'URL encoding' the room name before sending it in the WebSocket connection using the 'Uri.encodeComponent'.

Code will look like - "_channel = IOWebSocketChannel.connect(
'ws://192.168.0.11:8000/ws/chat_app/${Uri.encodeComponent(widget.room.roomName)}/');"
gsemerdz 17-Feb-24 12:48pm    
Tried that, yes it fixed the special characters issue, but still did not work. The error in the Terminal - "Not Found: /ws/chat_app/testUser's room/".

However, I have noticed something really weird, when I tried to access the URL that django runs on in my browser, I got the list of the URL patterns and the the WebSocket one looks really weird, any idea why? 'ws/ chat_app/<room_name>'. The whitespace between 'ws/' and 'chat_app'
Andre Oosthuizen 18-Feb-24 4:27am    
The whitespace in your WebSocket URL pattern is likely causing the issue. This can happen if there is an extra space in your 'routing.py' file or anywhere else in the URL pattern definition.

Your 'routing.py' file should look like this -
websocket_urlpatterns = [
    re_path(r'ws/chat_app/(?P<room_name>\w+)/$', ChatConsumer.as_asgi()),
]
.

Also check for whitespaces in other parts of your Django project that might be impacting the URL pattern.

Also make sure there are no accidental whitespaces in the 'urlpatterns' configuration in your main 'urls.py' file -
urlpatterns = [
    path('admin/', admin.site.urls),
    ...,
    path('ws/', include(websocket_urlpatterns)),
]


I hope this helps.
gsemerdz 18-Feb-24 11:48am    
Unfortunately, everything is as you showed in your comment and the whitespace is still there..

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900