現在仕事でWEBサービスを作るときはDjango一択な環境にいます。今度Websocketが必要になったのですがDjangoでWebsocketどうするんだってことで調べたところChannelsというライブラリを使うらしいです。Djangoのグループが作っているので安心感があります。Channelsは日本語でもいくつか記事がありましたが1.x時代のものでそのままでは動かなかったりしたのでチュートリアルを中心に試してみました。
ということで何回かにわけて(たぶん3回?)Django Channelsのチュートリアルをベースにちょっとだけ手を加えた内容をまとめていきます。また最終的には本番環境で動かせるようにnginx経由でwebsocketができるところまで持っていきます。
環境
以下の構成でやっていきます。
- Python 3.6
- Django 2.0.3
- Django Channels 2.0.2
また、どのような環境でも動作するようにDockerでの環境構築をしています。とりあえず動かしたいという場合はdenzow/channel-sampleのmasterブランチdocker-compose upで動かせると思います。
セットアップ
まず、必要なライブラリを導入しDjangoのプロジェクトを作る必要があります。
$ pip install django channels channels_redis $ django-admin startproject mysite .
さらに、チュートリアルの例ではchatというアプリをstartappで作成し、それを編集する流れになっています。ここまでを終わらせた状態のものをDockerの環境こみでstartブランチとして公開しましたので以下よりDLして展開し、docker-compose upすれば整います。
denzownoMacBook-Pro:~ denzow$ docker-compose up
実行すると、以下のように3つのコンテナが起動します。
denzownoMacBook-Pro:~ denzow$ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 92ad1eb59de1 channelsample_service_nginx "/start-nginx.sh" About a minute ago Up About a minute 80/tcp, 443/tcp, 0.0.0.0:8000->8000/tcp channelsample_service_nginx_1 11dd8ba126a0 channelsample_service "/app/docker/servi..." About a minute ago Up About a minute 0.0.0.0:3000->3000/tcp channelsample_service_1 77a55e623f6a channelsample_redis "docker-entrypoint..." About a minute ago Up About a minute 0.0.0.0:6379->6379/tcp channelsample_redis_1
channelsample_serviceがDjangoのコンテナで、channelsample_service_nginxがリバースプロキシ用のnginx、channelsample_redisはあとで必要になるredisサーバです。
では、channelsample_serviceに入って作業をしていきます。まずはとりあえず管理用のスーパーユーザを作っておきます。
denzownoMacBook-Pro:~ denzow$ docker exec -it channelsample_service_1 bash root@11dd8ba126a0:/app# ls root@11dd8ba126a0:/app# python manage.py createsuperuser
これで、Djang-adminが使えるはずです。ブラウザでhttp://localhost:3000/admin/にアクセスし、作成したユーザ・パスワードでログインできるか確認しておきます。

問題なくログインできたら次に進みます。
chatアプリケーションについて
現時点ではhttp://localhost:3000/chat/にアクセスするとチャットルーム名の入力を促すページが表示されます。
What chat room would you like to enter?
ただし、この時点ではルーム名を入力して進むと404になります。これはchat/urls.pyに以下のように空のルーティングの設定しかないためです。
# chat/urls.py from django.urls import path from . import views urlpatterns = [ path('', views.index, name='index'), ]
このファイルはsettings.pyのROOT_URLCONFに指定されているmysite.urlsで以下の様にincludeされています。
from django.contrib import admin from django.urls import path, include urlpatterns = [ path('admin/', admin.site.urls), path('chat/', include('chat.urls')) ]
そのため、現在はchat/ + ''のURLしかアクセスできない状態になっていますので、この動作は現時点では想定通りです。
Channelsの有効化
ではChannelsを有効化していきます。変更内容のcommitはこちらです。まずmysite/routing.pyとして以下のファイルを作成します。
from channels.routing import ProtocolTypeRouter application = ProtocolTypeRouter({ # (http->django views is added by default) })
ProtocolTypeRouterはDjangoのURLConfと同じようにリクエストを受け取った際にどのようなコードを実行するかをChannelsに伝えるものです。
では続いてsettings.pyを編集します。
INSTALLED_APPS = [
'channels', # <--- 追加
'chat',
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
]
# :
# 最下部
# :
# ASGIの起点を指定
# sys.path.append(APP_ROOT_PATH)してるからmysiteは省略できる
ASGI_APPLICATION = 'routing.application'
channelsをINSTALLED_APPSに追加し、ASGI_APPLICATIONに先程作成したrouting.pyのapplicationを指定します。これでChannelsが有効化されます。
runserverについて
channelsample_serviceコンテナは現時点でpython manage.py runserver 0.0.0.0:3000を実行しています。本番環境等ではuwsgi等のアプリケーションサーバを使用しますが、Channelsが扱うASGIというインターフェースはuwsgiで扱うことができないのです。一方で、channelsを導入した環境ではrunserverがASGI対応に自動的に置き換えられます。実際、起動時の出力を見てみると以下のようにASGI対応であることが表示されています。
service_1 | System check identified no issues (0 silenced). service_1 | March 24, 2018 - 13:55:26 service_1 | Django version 2.0.3, using settings 'mysite.settings' service_1 | Starting ASGI/Channels development server at http://0.0.0.0:3000/ <-- ASGI service_1 | Quit the server with CONTROL-C.
通常時のDjangoのrunserverの出力は以下のようにASGIの文字はありません。
service_1 | System check identified no issues (0 silenced). service_1 | March 25, 2018 - 14:31:33 service_1 | Django version 2.0.3, using settings 'mysite.settings' service_1 | Starting development server at http://0.0.0.0:3000/ service_1 | Quit the server with CONTROL-C.
channelsをINSTALLED_APPSに追加し、ASGI_APPLICATIONを設定した時点でrunserverがASGI開発ように置き換わっていることがわかります。なお、ASGI_APPLICATIONを定義せずにchannelsを追加するとrunserverがエラーで落ちるので注意します。
一旦まとめ
環境準備からChannelsの有効化までを簡単にまとめました。次回は実際にWebsocketでチャットルームを実装していくところまで進めていく予定です。