简体   繁体   中英

Django Channels WebSocket argument

I am trying out an example from the book Django By Example, Chapter 13 . There is an example there showing how to establish a socket for a chat room later on. Below is the code where I am sure the error comes from:

room.html

{% extends "base.html" %}

{% block title %}Chat room for "{{ course.title }}"{% endblock %}

{% block content %}
  <div id="chat">
  </div>
  <div id="chat-input">
    <input id="chat-message-input" type="text">
    <input id="chat-message-submit" type="submit" value="Send">
  </div>
{% endblock %}

{% block domready %}
  var url = 'ws://' + window.location.host + '/ws/chat/room/' + '{{ course.id }}/';
  var chatSocket = new WebSocket(url);
{% endblock %}

Below are the routing.py and consumer.py

routing.py

from django.urls import re_path
from . import consumers

websocket_urlpatterns = [
    re_path(r'ws/chat/room/(?P<course_id>\d+)/$', consumers.ChatConsumer),
]

consumer.py

import json
from channels.generic.websocket import AsyncWebsocketConsumer

class ChatConsumer(AsyncWebsocketConsumer):
    def connect(self):
        self.accept()

    def disconnect(self, close_code):
        pass

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

Below is the error message I got when running python manage.py runserver :

WebSocket HANDSHAKING /ws/chat/room/6/ [127.0.0.1:57288]
Exception inside application: object.__init__() takes exactly one argument (the instance to initialize)
Traceback (most recent call last):
  File "/home/xxx/.local/share/virtualenvs/chat-ayPz2iC9/lib/python3.8/site-packages/channels/staticfiles.py", line 44, in __call__
    return await self.application(scope, receive, send)
  File "/home/xxx/.local/share/virtualenvs/chat-ayPz2iC9/lib/python3.8/site-packages/channels/routing.py", line 71, in __call__
    return await application(scope, receive, send)
  File "/home/xxx/.local/share/virtualenvs/chat-ayPz2iC9/lib/python3.8/site-packages/channels/sessions.py", line 47, in __call__
    return await self.inner(dict(scope, cookies=cookies), receive, send)
  File "/home/xxx/.local/share/virtualenvs/chat-ayPz2iC9/lib/python3.8/site-packages/channels/sessions.py", line 254, in __call__
    return await self.inner(wrapper.scope, receive, wrapper.send)
  File "/home/xxx/.local/share/virtualenvs/chat-ayPz2iC9/lib/python3.8/site-packages/channels/auth.py", line 181, in __call__
    return await super().__call__(scope, receive, send)
  File "/home/xxx/.local/share/virtualenvs/chat-ayPz2iC9/lib/python3.8/site-packages/channels/middleware.py", line 26, in __call__
    return await self.inner(scope, receive, send)
  File "/home/xxx/.local/share/virtualenvs/chat-ayPz2iC9/lib/python3.8/site-packages/channels/routing.py", line 150, in __call__
    return await application(
  File "/home/xxx/.local/share/virtualenvs/chat-ayPz2iC9/lib/python3.8/site-packages/asgiref/compatibility.py", line 33, in new_application
    instance = application(scope)
  File "/home/xxx/.local/share/virtualenvs/chat-ayPz2iC9/lib/python3.8/site-packages/channels/generic/websocket.py", line 159, in __init__
    super().__init__(*args, **kwargs)
TypeError: object.__init__() takes exactly one argument (the instance to initialize)

This error occurs when I include the two lines in the block code {% block domready %} in the template room.html . Without these two lines, the websocket handshaking does not occur, and hence, no error.

It seems from the error, the socket instantiation asks for only ONE argument. But it seems the code new WebSocket(url) did give one argument. Does anyone know if something is missing? Thanks.

Update after @Iain Shevington :

Below is the new error message after adding

websocket_urlpatterns = [
    re_path(r'ws/chat/room/(?P<course_id>\d+)/$', consumers.ChatConsumer.as_asgi()),
]
WebSocket HANDSHAKING /ws/chat/room/6/ [127.0.0.1:57750]
Exception inside application: object NoneType can't be used in 'await' expression
Traceback (most recent call last):
  File "/home/xxx/.local/share/virtualenvs/chat-ayPz2iC9/lib/python3.8/site-packages/channels/staticfiles.py", line 44, in __call__
    return await self.application(scope, receive, send)
  File "/home/xxx/.local/share/virtualenvs/chat-ayPz2iC9/lib/python3.8/site-packages/channels/routing.py", line 71, in __call__
    return await application(scope, receive, send)
  File "/home/xxx/.local/share/virtualenvs/chat-ayPz2iC9/lib/python3.8/site-packages/channels/sessions.py", line 47, in __call__
    return await self.inner(dict(scope, cookies=cookies), receive, send)
  File "/home/xxx/.local/share/virtualenvs/chat-ayPz2iC9/lib/python3.8/site-packages/channels/sessions.py", line 254, in __call__
    return await self.inner(wrapper.scope, receive, wrapper.send)
  File "/home/xxx/.local/share/virtualenvs/chat-ayPz2iC9/lib/python3.8/site-packages/channels/auth.py", line 181, in __call__
    return await super().__call__(scope, receive, send)
  File "/home/xxx/.local/share/virtualenvs/chat-ayPz2iC9/lib/python3.8/site-packages/channels/middleware.py", line 26, in __call__
    return await self.inner(scope, receive, send)
  File "/home/xxx/.local/share/virtualenvs/chat-ayPz2iC9/lib/python3.8/site-packages/channels/routing.py", line 150, in __call__
    return await application(
  File "/home/xxx/.local/share/virtualenvs/chat-ayPz2iC9/lib/python3.8/site-packages/channels/consumer.py", line 94, in app
    return await consumer(scope, receive, send)
  File "/home/xxx/.local/share/virtualenvs/chat-ayPz2iC9/lib/python3.8/site-packages/channels/consumer.py", line 58, in __call__
    await await_many_dispatch(
  File "/home/xxx/.local/share/virtualenvs/chat-ayPz2iC9/lib/python3.8/site-packages/channels/utils.py", line 51, in await_many_dispatch
    await dispatch(result)
  File "/home/xxx/.local/share/virtualenvs/chat-ayPz2iC9/lib/python3.8/site-packages/channels/consumer.py", line 73, in dispatch
    await handler(message)
  File "/home/xxx/.local/share/virtualenvs/chat-ayPz2iC9/lib/python3.8/site-packages/channels/generic/websocket.py", line 175, in websocket_connect
    await self.connect()
TypeError: object NoneType can't be used in 'await' expression
WebSocket DISCONNECT /ws/chat/room/6/ [127.0.0.1:57750]

You need to call as_asgi() when you pass your consumer to websocket_urlpatterns

websocket_urlpatterns = [
    re_path(r'ws/chat/room/(?P<course_id>\d+)/$', consumers.ChatConsumer.as_asgi()),
]

From the docs :

We call the as_asgi() classmethod when routing our consumers. This returns an ASGI wrapper application that will instantiate a new consumer instance for each connection or scope. This is similar to Django's as_view(), which plays the same role for per-request instances of class-based views.

EDIT: You are using an async consumer, the methods on an async consumer must be coroutines (using async and await)

class ChatConsumer(AsyncWebsocketConsumer):
    async def connect(self):
        await self.accept()

    # receive message from WebSocket
    async def receive(self, text_data):
        text_data_json = json.loads(text_data)
        message = text_data_json['message']
        await self.send(text_data=json.dumps({'message': message}))

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM