美文网首页python之路
使用channels创建聊天室

使用channels创建聊天室

作者: 非鱼2018 | 来源:发表于2021-10-16 11:37 被阅读0次

参考:https://channels.readthedocs.io/en/stable/tutorial/index.html
官方文档只是创建了个room,没有昵称,看了示例后自己加了个昵称,这样看的更直观些

先看下效果:


Image.png Image.png

1.安装
djano版本:3.1
python3 -m django --version
3.1
安装channels
pyhton3 -m pip install channels
安装后需要把channels添加到settings.py文件的installapp

2.创建工程
python manage.py startproject mysite
python manage.py startapp chat
chat加入到setting的instalapp
chat目录增加模板文件
templates/
chat/
index.html

<!-- chat/templates/chat/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="you-name-input" type="text" size="100"><br>
    <input id="room-name-submit" type="button" value="Enter">

    <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;
            var userName = document.querySelector('#you-name-input').value;
            window.location.pathname = '/chat/' + roomName +'/'+userName;
        };
    </script>
</body>
</html>


room.html

<!-- chat/templates/chat/room.html -->
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8"/>
    <title>Chat Room</title>
</head>
<body>
    <textarea id="chat-log" cols="100" rows="20"></textarea><br>
    <input id="chat-message-input" type="text" size="100"><br>
    <input id="chat-message-submit" type="button" value="Send">
    {{ room_name|json_script:"room-name" }}
    {{ user_name|json_script:"user-name" }}
    <script>
        const roomName = JSON.parse(document.getElementById('room-name').textContent);
        const userName = JSON.parse(document.getElementById('user-name').textContent);

        const chatSocket = new WebSocket(
            'ws://'
            + window.location.host
            + '/ws/chat/'
            + roomName
            + '/'+userName+'/'
        );

        chatSocket.onmessage = function(e) {
            const data = JSON.parse(e.data);
            document.querySelector('#chat-log').value += (data.message + '\n');
        };

        chatSocket.onclose = function(e) {
            console.error('Chat socket closed unexpectedly');
        };

        document.querySelector('#chat-message-input').focus();
        document.querySelector('#chat-message-input').onkeyup = function(e) {
            if (e.keyCode === 13) {  // enter, return
                document.querySelector('#chat-message-submit').click();
            }
        };

        document.querySelector('#chat-message-submit').onclick = function(e) {
            const messageInputDom = document.querySelector('#chat-message-input');
            const message = messageInputDom.value;
            chatSocket.send(JSON.stringify({
                'message': message
            }));
            messageInputDom.value = '';
        };
    </script>
</body>
</html>

过滤器json_script:
此处意思为生成一个类似页面元素,值就是传过来的值,id为room_name,
这里我加了一个吧用户昵称也传过来


Image.png

2.路由

chat/urls.py

from django.urls import path

from . import views

urlpatterns = [
    path('', views.index, name='index'),
    path('<str:room_name>/<str:user_name>', views.room, name='room'),
]

3.视图

from django.shortcuts import render

# Create your views here.
# chat/views.py


def index(request):
    return render(request, 'chart/index.html')

def room(request, room_name,user_name):
    return render(request, 'chart/room.html', {
        'room_name': room_name,
        'user_name': user_name
    })

4.主路由,mysite/urls.py
path('chat/', include('chart.urls')),

5,mysite/asgi.py

import os

from channels.auth import AuthMiddlewareStack
from channels.routing import ProtocolTypeRouter, URLRouter
from django.core.asgi import get_asgi_application
import chart.routing

os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mysite.settings")

application = ProtocolTypeRouter({
  "http": get_asgi_application(),
  "websocket": AuthMiddlewareStack(
        URLRouter(
            chart.routing.websocket_urlpatterns
        )
    ),
})

6.chat/rounting.py

# chat/routing.py
from django.urls import re_path

from . import consumers

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

7consumer.py

# chat/consumers.py
import json
from channels.generic.websocket import AsyncWebsocketConsumer

class ChatConsumer(AsyncWebsocketConsumer):
    async def connect(self):
        self.room_name = self.scope['url_route']['kwargs']['room_name']
        self.user_name = self.scope['url_route']['kwargs']['user_name']
        self.room_group_name = 'chat_%s' % self.room_name
        print('roomname',self.room_name)
        print('user_name', self.user_name)
        # Join room group
        await self.channel_layer.group_add(
            self.room_group_name,
            self.channel_name
        )

        await self.accept()

    async def disconnect(self, close_code):
        # Leave room group
        await self.channel_layer.group_discard(
            self.room_group_name,
            self.channel_name
        )

    # Receive message from WebSocket
    async def receive(self, text_data):
        text_data_json = json.loads(text_data)
        message = text_data_json['message']

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

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

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

8.安装redis
docker 安装:
docker run -p 6379:6379 -d redis:5
如果是windows本地安装,注意需要安装5.0版本以上的
否则运行程序时会出现类似:ERR unknown command 'BZPOPMIN'的错误
redis5.0 windows安装
https://blog.csdn.net/qq_26373925/article/details/109269459
https://github.com/tporadowski/redis/releases
安装后启动

image.png

安装channels-redis
python3 -m pip install channels_redis

9.# mysite/settings.py

ASGI_APPLICATION = 'mysite.asgi.application'
CHANNEL_LAYERS = {
    'default': {
        'BACKEND': 'channels_redis.core.RedisChannelLayer',
        'CONFIG': {
            "hosts": [('127.0.0.1', 6379)],
        },
    },
}

10.启动server,python manage.py run server

image.png
image.png

使用两台机器,或打开浏览器两个页签,分别输入两同的room名称不同的昵称,就可以开始聊天了

相关文章

网友评论

    本文标题:使用channels创建聊天室

    本文链接:https://www.haomeiwen.com/subject/ojzwnltx.html