DjangoのWebsocketハンドシェイクエラーを解決する

DjangoでWebsocketを使う場合は「Channels」を使うのが一般的らしい。
今回は「Channels」を使って実装したときに以下のようなエラーに遭遇したので、同じ悩みを持つ方へ解決方法を共有しておく。

Exception inside application: object.__init__() takes exactly one argument (the instance to initialize)
目次

Exception inside application...

このエラーが起きる原因はおそらくWebsocketConsumerクラスを継承してなんやかんやしてる場合です。
「Channels」を使ってwebsocketを実装する方法はいくつかありますが、WebsocketConsumerクラスを継承すると割とサクッと実装できる気がします。ですが、ここで今回のようなエラーに遭遇する方もいるのではないでしょうか。

consumers.py
class WSConsumer(WebsocketConsumer):
    def connect(self):
        self.accept()

    def disconnect(self, close_code):
        pass

    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
        }))
routing.py
from django.urls import path
from . import consumers


websocket_urlpatterns = [
    path('ws/<slug:room_name>/', consumers.WSConsumer),    #後ほど説明しますが、この部分が問題です。
]

WebSocketのテストとしてオウム返しに入力値を表示するプログラムを実装したときの一部分になります。
WebsocketConsumerを継承しています。

原因はpython3.6以上を使っているから

今回のException inside application: object.init() takes exactly one argument (the instance to initialize)エラーの原因はpython3.6以上を使っているからでした。

python3.6からWebsocketConsumerクラスの呼び出し方が変更されたようです。

以下のようにrouting.pyのクラス呼び出し部分を変更します。as_asgi()を付けます。

websocket_urlpatterns = [
    path('ws/<slug:room_name>/', consumers.WSConsumer.as_asgi()),
]

これで、python3.6以上で「Channels」を使ったWebSocketハンドシェイクエラーが解決しました。

pythonの互換性を考慮する

python3.6未満の場合はこれだと動きません。なので、どのバージョンでも動くようにするためには以下のように実装します。お使いの環境等を考慮して必要であれば実装してみてください。

routing.py
from django.urls import path
from . import consumers

if float(platform.python_version()[0:3]) > 3.6:
    cons = consumers.WSConsumer.as_asgi()
else:
    cons = consumers.WSConsumer

websocket_urlpatterns = [
    path('ws/<slug:room_name>/', cons),
]

これで解決。ばいちゃ

この記事が気に入ったら
フォローしてね!

よかったらシェアしてね!

コメント

コメントする

目次
閉じる