yoshiislandblog.net
元営業の駆け出しアラサーSEが、休日にMACと戯れた際の殴り書きメモ。日々勉強。日々進歩。

この記事は3年以上前に書かれた記事で内容が古い可能性があります

DjangoでChatアプリを作る5(チャットの投稿が別画面でもリアルタイムに反映されるまで)

2019-02-18

DjangoでChatアプリを作る4(チャットの投稿ができるまで)の続き

CHANNEL_LAYERSをsettings.pyに追記する

% vim mysite/settings.py
% tail -8 mysite/settings.py
CHANNEL_LAYERS = {
    'default': {
        'BACKEND': 'channels_redis.core.RedisChannelLayer',
        'CONFIG': {
            "hosts": [('0.0.0.0', 6379)],
        },
    },
}

あれ、エラー

web_1  |   Cannot import BACKEND 'channels_redis.core.RedisChannelLayer' specified for default
web_1  | WebSocket DISCONNECT /ws/chat/lobby/ []

channels_redisを忘れてた

% vim requirements.txt

★部分追記

% cat requirements.txt
Django
psycopg2
python-decouple
social-auth-app-django
channels
channels_redis ★

docker-compose buildとdocker-compose upで立ち上げ直す

次はこんなエラーが

web_1  |     raise OSError(err, f'Connect call failed {address}')
web_1  |   [Errno 111] Connect call failed ('0.0.0.0', 6379)
web_1  | WebSocket DISCONNECT /ws/chat/lobby/ [ ]

0.0.0.0ではなく、’redis’と記載する(★部分追記)

% tail -8 mysite/settings.py
CHANNEL_LAYERS = {
    'default': {
        'BACKEND': 'channels_redis.core.RedisChannelLayer',
        'CONFIG': {
            "hosts": [('redis', 6379)], ★
        },
    },
}

次はこれ

web_1  |     for res in _socket.getaddrinfo(host, port, family, type, proto, flags):
web_1  |   [Errno -2] Name or service not known
web_1  | WebSocket DISCONNECT /ws/chat/lobby/ [ ]

redisサービスをあげてなかった(★部分追記)

% cat docker-compose.yml
version: '3'

services:
  db:
    image: postgres
  redis: ★
    image: redis:2.8 ★
    ports: ★
      - "6379:6379" ★
  web:
    build: .
    command: python3 manage.py runserver 0.0.0.0:8000
    volumes:
      - .:/code
    ports:
      - "8000:8000"
    depends_on:
      - db
      - redis ★

docker-compose buildとdocker-compose upで立ち上げ直す
docker-compose upでこんなん出てくる

redis_1  |                 _._
redis_1  |            _.-``__ ''-._
redis_1  |       _.-``    `.  `_.  ''-._           Redis 2.8.23 (00000000/0) 64 bit
redis_1  |   .-`` .-```.  ```\/    _.,_ ''-._
redis_1  |  (    '      ,       .-`  | `,    )     Running in stand alone mode
redis_1  |  |`-._`-...-` __...-.``-._|'` _.-'|     Port: 6379
redis_1  |  |    `-._   `._    /     _.-'    |     PID: 1
redis_1  |   `-._    `-._  `-./  _.-'    _.-'
redis_1  |  |`-._`-._    `-.__.-'    _.-'_.-'|
redis_1  |  |    `-._`-._        _.-'_.-'    |           http://redis.io
redis_1  |   `-._    `-._`-.__.-'_.-'    _.-'
redis_1  |  |`-._`-._    `-.__.-'    _.-'_.-'|
redis_1  |  |    `-._`-._        _.-'_.-'    |
redis_1  |   `-._    `-._`-.__.-'_.-'    _.-'
redis_1  |       `-._    `-.__.-'    _.-'
redis_1  |           `-._        _.-'
redis_1  |               `-.__.-'

最後はこの文言出てくる

web_1    | Django version 2.1.7, using settings 'mysite.settings'
web_1    | Starting ASGI/Channels version 2.1.7 development server at http://0.0.0.0:8000/
web_1    | Quit the server with CONTROL-C.

consumers.pyをコピペし直す

% vim chat/consumers.py
% cat chat/consumers.py
from asgiref.sync import async_to_sync
from channels.generic.websocket import WebsocketConsumer
import json

class ChatConsumer(WebsocketConsumer):
    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):
        text_data_json = json.loads(text_data)
        message = text_data_json['message']

        # Send message to room group
        async_to_sync(self.channel_layer.group_send)(
            self.room_group_name,
            {
                'type': 'chat_message',
                'message': message
            }
        )

    # Receive message from room group
    def chat_message(self, event):
        message = event['message']

        # Send message to WebSocket
        self.send(text_data=json.dumps({
            'message': message
        }))

できた、2画面で同期とれている

Safariの方

Chromeの方でhiと送信する

すると、Safariの方でも反映されている

最終的なディレクトリ構造はこんな感じ

% tree
.
└── mysite
    ├── Dockerfile
    ├── chat
    │   ├── __init__.py
    │   ├── __pycache__
    │   ├── consumers.py
    │   ├── routing.py
    │   ├── templates
    │   │   └── chat
    │   │       ├── index.html
    │   │       └── room.html
    │   ├── urls.py
    │   ├── views.py
    ├── docker-compose.yml
    ├── manage.py
    ├── mysite
    │   ├── __init__.py
    │   ├── __pycache__
    │   ├── asgi.py
    │   ├── login
    │   │   ├── __pycache__
    │   │   └── views.py
    │   ├── routing.py
    │   ├── settings.py
    │   ├── templates
    │   │   ├── base.html
    │   │   ├── home.html
    │   │   └── registration
    │   │       ├── login.html
    │   ├── urls.py
    │   └── wsgi.py
    ├── requirements.txt

次はせっかくなので、ログインユーザだけチャットできる世界を作りたい