ぽよメモ

レガシーシステム考古学専攻

Django 2.0 + Channels 2.1 でチュートリアルやっていく(1)

はじめに

channelsの公式チュートリアルを順番にやっていこうというだけのものです.Djangoの基礎知識に関しては一切触れません.ご了承ください.
そろそろWebSocketもやらないとね?って天の声に言われたので,今回はTutorial Part 1: Basic Setupからやっていきます.Django 2.0を使用しているので,チュートリアルとところどころコードが違います.

環境構築

あらかじめ断っておくとWindowsではやりません.

仮想環境としてvenvを使用していきます.

$ python3 -V
3.6.0
$ python3 -m venv env
$ source env/bin/activate

必要なライブラリをインストールします

$ pip install --upgrade pip
$ pip install django channels
$ pip freeze
asgiref==2.3.0
async-timeout==2.0.1
attrs==18.1.0
autobahn==18.4.1
Automat==0.6.0
channels==2.1.1
constantly==15.1.0
daphne==2.1.1
Django==2.0.5
hyperlink==18.0.0
idna==2.6
incremental==17.5.0
pytz==2018.4
six==1.11.0
Twisted==18.4.0
txaio==2.10.0
zope.interface==4.5.0

今回作るもの

In this tutorial we will build a simple chat server. It will have two pages:

・ An index view that lets you type the name of a chat room to join.
・ A room view that lets you see messages posted in a particular chat room.

The room view will use a WebSocket to communicate with the Django server and listen for any messages that are posted.

とあるように,チャットアプリケーションを作成します.

仕様

  • 2つのページを作る
    • 参加するチャットルームの名前を入力する初期ページ
    • 特定のルームに投稿されたメッセージを見れるルームページ
  • ルームのページではWebSocketを使用してDjangoサーバとの通信を行う

Tutorial Part1: Basic Setup

アプリケーション初期設定

プロジェクト名はchannels_tutorial1,アプリケーション名はchatとします.

$ django-admin startproject channels_tutorial1
$ cd channels_tutorial1
$ python manage.py startapp chat
$ tree -L 2
.
├── channels_tutorial1
│   ├── __init__.py
│   ├── __pycache__
│   ├── settings.py
│   ├── urls.py
│   └── wsgi.py
├── chat
│   ├── __init__.py
│   ├── admin.py
│   ├── apps.py
│   ├── migrations
│   ├── models.py
│   ├── tests.py
│   └── views.py
└── manage.py

4 directories, 11 files

settings.pyを日本語環境向けに編集します.106~108行目あたりです.

LANGUAGE_CODE = 'ja-jp'

TIME_ZONE = 'Asia/Tokyo'

シークレットキーがそのまま埋め込まれているのが精神的に良くないのでdotenvで分離します.

$ pip install python-dotenv

manage.pyと同じディレクトリに下記のような.envファイルを用意します.値は適当に入れてください.

SECRET_KEY=f%1(dv)6-)sadf3-c+vr*8b1j&2=^38o^&i!ekni6%=y^sxogsdif
DEBUG=True

dotenv.load_dotenv.envファイルをロードします.

import os
import dotenv

BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))

# .envを読み込み
dotenv.load_dotenv(os.path.join(BASE_DIR, '.env'))

SECRET_KEY = os.getenv('SECRET_KEY')
DEBUG = os.getenv('DEBUG', 'False').lower() == 'true'

INSTALLED_APPSchatアプリを追加します

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'chat'
]

初期ページ追加

chatディレクトリの中にテンプレートを入れるためのtemplatesディレクトリを作成し,更に中にchatディレクトリを作成,index.htmlを配置します.

$ pwd
/path/to/channels_tutorial1
$ cd chat
$ mkdir templates
$ cd templates
$ mkdir chat
$ touch chat/index.html

index.htmlを下記のように編集します.

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8"/>
    <title>Chat Rooms</title>
</head>
<body>
    What chat room would you like to enter?<br/>
    <input id="room-name-input" type="text" size="100"/><br/>
    <input id="room-name-submit" type="button" value="Enter"/>
</body>
<script>
    document.querySelector('#room-name-input').focus();
    document.querySelector('#room-name-input').onkeyup = function(e) {
        if (e.keyCode === 13) {  // enter, return
            document.querySelector('#room-name-submit').click();
        }
    };

    document.querySelector('#room-name-submit').onclick = function(e) {
        var roomName = document.querySelector('#room-name-input').value;
        window.location.pathname = '/chat/' + roomName + '/';
    };
</script>
</html>

chat/views.pyに下記の様にindex.htmlをrenderして返す関数を定義します.

from django.shortcuts import render


def index(request):
    return render(request, 'chat/index.html', {})

chat/urls.pyを作成し,下記の様にindexへのurlpatternを定義します.

from django.urls import path

from .views import index


urlpatterns = [
    # 元のコードは→url(r'^$', views.index, name='index'),
    path('', index, name='index'),
]

settings.pyと同階層にあるurls.pyがルートになっているので,ここからchat/urls.pyを取り込みます.

from django.contrib import admin
from django.urls import path, include

from chat import urls as chat_urls


urlpatterns = [
    # 元のコードは→url(r'^chat/', include('chat.urls')),
    path('chat/', include(chat_urls)),
    # 元のコードは→url(r'^admin/', admin.site.urls),
    path('admin/', admin.site.urls),
]

ここまで出来たら一度runserverで動かして,http://127.0.0.1:8000/chat/にアクセスしてみます.

$ python manage.py runserver

System check identified no issues (0 silenced).
May 05, 2018 - 01:07:36
Django version 2.0.5, using settings 'channels_tutorial1.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.

下記の様なページが表示されると思います.

f:id:pudding_info:20180505011127p:plain

ASGI/Channelsサーバの起動

ここまでは標準のDjangoの機能を使用してきましたが,ここからはchannelsモジュールを使用して行きます.

まず,channelsが用いるルーティングファイルを記述します.これはurls.pyのようなものに相当するようです.channels_tutorial1/routing.pyを作成し下記の様に編集します.

from channels.routing import ProtocolTypeRouter

application = ProtocolTypeRouter({
    # (http->django views is added by default)
})

INSTALLED_APPSchannelsを追加し,ASGI_APPLICATIONを定義します.

INSTALLED_APPS = [
    # 省略
    'chat',
    'channels',
]

ASGI_APPLICATION = 'channels_tutorial1.routing.application'

runserverしてみると,先ほどとは違う,ASGI/Channelsサーバが起動します((チュートリアルではこれがいくつかのrunserverをラップしてしまうようなコマンドに対して競合する可能性を示唆しています.例えば静的ファイルを配信する設定を簡便にするwhitenoiseなどがその筆頭のようで,その場合はchannelsINSTALLED_APPSの先頭に持ってくる,それらのアプリケーションを削除するなどが対策として上げられています.)).

$ python manage.py runserver
Performing system checks...

System check identified no issues (0 silenced).
May 05, 2018 - 01:16:55
Django version 2.0.5, using settings 'channels_tutorial1.settings'
Starting ASGI/Channels version 2.1.1 development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.
2018-05-05 01:16:55,548 - INFO - server - HTTP/2 support not enabled (install the http2 and tls Twisted extras)
2018-05-05 01:16:55,548 - INFO - server - Configuring endpoint tcp:port=8000:interface=127.0.0.1
2018-05-05 01:16:55,555 - INFO - server - Listening on TCP address 127.0.0.1:8000

再びhttp://127.0.0.1:8000にアクセスし,表示されれば完了です.次回Part 2に続きます.

poyo.hatenablog.jp