title: Django ValueError: No route found for path 'ws/chat//'
body: <p>I'm working on making a simple chat app using <a href="https://www.youtube.com/watch?v=xrKKRRC518Y" rel="nofollow noreferrer">this tutorial from youtube</a> (github link here: <a href="https://github.com/justdjango/justchat" rel="nofollow noreferrer">LINK</a>). One potential issue is that the tutorial uses 2.x version of django but i have 3.1.7, but I had it working pretty well and was close, but then started getting this error:</p>
  <p><code>ValueError: No route found for path 'ws/chat//'</code></p>
  <p>When looking at my terminal, it keeps trying to reconnect over and over, possible becaues I'm using the <a href="https://github.com/joewalnes/reconnecting-websocket" rel="nofollow noreferrer">ReconnectingWebSocket github javascript code</a>. When I run redis-cli and type 'ping', I get 'PONG' in return so I think that is working properly.</p>
  <p><strong>Below is my code:</strong></p>
  <p><strong>routing.py (I believe this seems most likely where the issue is)</strong></p>
  <pre><code>from django.urls import re_path
  from . import consumers
  
  websocket_urlpatterns = [
      re_path(r'ws/chat/(?P&lt;room_name&gt;\w+)/$', consumers.ChatConsumer.as_asgi()), #new django
  ]
  </code></pre>
  <p><strong>wsgi.py:</strong></p>
  <pre><code>import os
  from django.core.wsgi import get_wsgi_application
  os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'django_project.settings')
  application = get_wsgi_application()
  </code></pre>
  <p><strong>settings.py:</strong></p>
  <pre><code>WSGI_APPLICATION = 'django_project.wsgi.application'
  ASGI_APPLICATION = 'django_project.asgi.application' # older version of django: 'django_project.routing.application'
  # Channels redis config:
  CHANNEL_LAYERS = {
      'default': {
          'BACKEND': 'channels_redis.core.RedisChannelLayer',
          'CONFIG': {
              &quot;hosts&quot;: [('127.0.0.1', 6379)],
          },
      },
  }
  </code></pre>
  <p><strong>views.py:</strong></p>
  <h1>chat/views.py</h1>
  <p>from django.shortcuts import render
  import json
  from django.contrib.auth.decorators import login_required
  from django.utils.safestring import mark_safe</p>
  <p>def index(request):
  return render(request, 'chat/index.html')</p>
  <p>@login_required
  def room(request, room_name):
  return render(request, 'chat/room.html', {
  'room_name_json': room_name
  })</p>
  <p><strong>urls.py</strong>
  from django.urls import path, include
  from . import views</p>
  <pre><code>app_name = 'chat'
  
  urlpatterns = [
      path('chat/', views.index, name='index'),
      path('chat/&lt;str:room_name&gt;/', views.room, name='room'),
  ]
  </code></pre>
  <p><strong>room.html:</strong></p>
  <pre><code>{% load static %}
  &lt;!DOCTYPE html&gt;
  &lt;html&gt;
  &lt;head&gt;
      &lt;meta charset=&quot;utf-8&quot;/&gt;
      &lt;title&gt;Chat Room&lt;/title&gt;
  &lt;/head&gt;
  &lt;body&gt;
      &lt;script src=&quot;{% static '/reconnecting_websockets.js' %}&quot;&gt;&lt;/script&gt;
      &lt;textarea id=&quot;chat-log&quot; cols=&quot;100&quot; rows=&quot;20&quot;&gt;&lt;/textarea&gt;&lt;br&gt;
      &lt;input id=&quot;chat-message-input&quot; type=&quot;text&quot; size=&quot;100&quot;&gt;&lt;br&gt;
      &lt;input id=&quot;chat-message-submit&quot; type=&quot;button&quot; value=&quot;Send&quot;&gt;
      {{ room_name|json_script:&quot;room-name&quot; }}
      &lt;script&gt;
          const roomName = JSON.parse(document.getElementById('room-name').textContent);
  
          const chatSocket = new ReconnectingWebSocket(
              'ws://'
              + window.location.host
              + '/ws/chat/'
              + roomName
              + '/'
          );
  
          chatSocket.onmessage = function(e) {
              const data = JSON.parse(e.data);
              document.querySelector('#chat-log').value += (data.message + '\n'); //grabbing the textarea with id(#) 'chat-log'
          };
  
          chatSocket.onclose = function(e) {
              console.error('Chat socket closed unexpectedly');
          };
  
          document.querySelector('#chat-message-input').focus();
          document.querySelector('#chat-message-input').onkeyup = function(e) {
              if (e.keyCode === 13) {  // enter, return
                  document.querySelector('#chat-message-submit').click();
              }
          };
  
          document.querySelector('#chat-message-submit').onclick = function(e) {
              const messageInputDom = document.querySelector('#chat-message-input');
              const message = messageInputDom.value;
              chatSocket.send(JSON.stringify({
                  'message': message,
                  'command': 'fetch_messages'
              }));
              messageInputDom.value = ''; //reset value to empty string
          };
      &lt;/script&gt;
  &lt;/body&gt;
  &lt;/html&gt;
  </code></pre>
  <p><strong>consumers.py:</strong></p>
  <h1>chat/consumers.py</h1>
  <p>import json
  from asgiref.sync import async_to_sync
  from channels.generic.websocket import WebsocketConsumer
  from .models import Message
  from django.contrib.auth.models import User</p>
  <p>class ChatConsumer(WebsocketConsumer):</p>
  <pre><code>def fetch_messages(self, data):
      messages = Message.last_10_messages(self)
      content = {
          'command': 'messages',
          'messages': self.messages_to_json(messages)
      }
      self.send_message(content)
  
  
  def new_message(self, data):
      author_user = User.objects.filter(username='admin')[0]
      message = Message.objects.create(author=author_user, content=data['message'])
      content = {
          'command': 'new_message',
          'message': self.message_to_json(message)
      }
      return self.send_chat_message(content)
  
  
  def messages_to_json(self, messages):
      result = []
      for message in messages:
          result.append(self.message_to_json(message))
      return result
  
  def message_to_json(self, message):
      return {
          'author': message.author.username,
          'content': message.content,
          'timestamp': str(message.timestamp)
      }
  
  commands = {
      'fetch_messages': fetch_messages,
      'new_message': new_message
  }
  
  
  def connect(self):
      self.room_name = self.scope['url_route']['kwargs']['room_name']
      self.room_group_name = 'chat_%s' % self.room_name
  
      # Join room group
      async_to_sync(self.channel_layer.group_add)(
          self.room_group_name,
          self.channel_name
      )
  
      self.accept()
  
  def disconnect(self, close_code):
      # Leave room group
      async_to_sync(self.channel_layer.group_discard)(
          self.room_group_name,
          self.channel_name
      )
  
  # Receive message from WebSocket
  def receive(self, text_data):
      data = json.loads(text_data)
      self.commands[data['command']](self, data) # either fetch_messages or new_message
  
  def send_chat_message(self, message):
      print('in send_chat_message')
      async_to_sync(self.channel_layer.group_send)( # Send message to room group
          self.room_group_name,
          {
              'type': 'chat_message',
              'message': message
          }
      )
  
  def send_message(self, message):
      print('message: ' + str(message))
      self.send(text_data=json.dumps(message))
  
  # Receive message from room group
  def chat_message(self, event):
      message = event['message']
      content1 = message['message']
      content2 = content1['content']
      #self.send(text_data=json.dumps(content2)) # Send message to WebSocket
      self.send(text_data=json.dumps(content2)) # Send message to WebSocket
  </code></pre>