详解Django-channels 实现WebSocket实例


Posted in Python onAugust 22, 2019

引入

先安装三个模块

pip install channels

pip install channels_redis

pip install pywin32

创建一个Django项目和一个app

项目名随意,app名随意。这里项目名为 django_websocket_demo ,app名 chat

把app文件夹下除了 views.py 和 __init__.py 的文件都删了,最终项目目录结构如下:

django_websocket_demo/
  manage.py
  django_websocket_demo/
    __init__.py
    settings.py
    urls.py
    wsgi.py
  chat/
    __init__.py
    views.py

在app下新建一个templates文件夹用来存放HTML页面:

chat/
  __init__.py
  templates/
    chat/
      index.html
  views.py

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="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;
      window.location.pathname = '/chat/' + roomName + '/';
    };
  </script>
</body>
</html>

在 chat/views.py 中添加视图函数:

from django.shortcuts import render

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

添加 chat/urls.py 文件并设置路由信息:

from django.urls import re_path

from . import views

urlpatterns = [
  re_path(r'^$', views.index, name='index'),
]

在项目路由 django_websocket_demo/urls.py 中配置路由信息:

from django.conf.urls import include, url
from django.contrib import admin

urlpatterns = [
  url(r'^chat/', include('chat.urls')),
  url(r'^admin/', admin.site.urls),
]

在 settings.py 文件同级目录下新建 routing.py 文件,内容如下:

from channels.routing import ProtocolTypeRouter

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

把 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',
]

在   settings.py 文件中,添加如下配置项:

# django_websocket_demo/settings.py
# Channels
# Channels
ASGI_APPLICATION = 'django_websocket_demo.routing.application'

创建聊天页面

创建一个 chat/templates/chat/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"/>
</body>
<script>
  var roomName = {{ room_name_json }};

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

  chatSocket.onmessage = function(e) {
    var data = JSON.parse(e.data);
    var message = data['message'];
    document.querySelector('#chat-log').value += (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) {
    var messageInputDom = document.querySelector('#chat-message-input');
    var message = messageInputDom.value;
    chatSocket.send(JSON.stringify({
      'message': message
    }));

    messageInputDom.value = '';
  };
</script>
</html>

在 chat/views.py 中添加一个处理 room的视图函数:

from django.shortcuts import render
from django.utils.safestring import mark_safe
import json

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

def room(request, room_name):
  return render(request, 'chat/room.html', {
    'room_name_json': mark_safe(json.dumps(room_name))
  })

在 chat/urls.py 中注册路由

from django.urls import re_path

from . import views

urlpatterns = [
  re_path(r'^$', views.index, name='index'),
  re_path(r'^(?P<room_name>[^/]+)/$', views.room, name='room'),
]

新建 chat/consumers.py 文件,添加如下内容:

from channels.generic.websocket import AsyncWebsocketConsumer
import json

class ChatConsumer(AsyncWebsocketConsumer):
  async 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
    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': 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
    }))

新建一个 chat/routing.py 文件,添加以下内容:

from django.urls import re_path

from . import consumers

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

将 django_websocket_demo/routing.py 文件中修改为以下内容:

from channels.auth import AuthMiddlewareStack
from channels.routing import ProtocolTypeRouter, URLRouter
import chat.routing

application = ProtocolTypeRouter({
  # (http->django views is added by default)
  'websocket': AuthMiddlewareStack(
    URLRouter(
      chat.routing.websocket_urlpatterns
    )
  ),
})

配置redis

在本地6379端口启动redis : redis-server

在 settings.py 中添加如下配置:

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

最后启动Django项目

使用多个浏览器打开http://127.0.0.1:8000/chat/lobby/ ,开始实时聊天吧。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
Python中的tuple元组详细介绍
Feb 02 Python
Windows下PyMongo下载及安装教程
Apr 27 Python
python读取和保存视频文件
Apr 16 Python
python将list转为matrix的方法
Dec 12 Python
selenium python 实现基本自动化测试的示例代码
Feb 25 Python
Django 开发环境配置过程详解
Jul 18 Python
Python 使用type来定义类的实现
Nov 19 Python
Python reversed函数及使用方法解析
Mar 17 Python
Jupyter notebook如何实现指定浏览器打开
May 13 Python
pycharm 配置svn的图文教程(手把手教你)
Jan 15 Python
Python中Matplotlib的点、线形状、颜色以及绘制散点图
Apr 07 Python
Python经常使用的一些内置函数
Apr 11 Python
解决python3 requests headers参数不能有中文的问题
Aug 21 #Python
python通过robert、sobel、Laplace算子实现图像边缘提取详解
Aug 21 #Python
Python爬虫:url中带字典列表参数的编码转换方法
Aug 21 #Python
Python GUI学习之登录系统界面篇
Aug 21 #Python
Python爬虫:将headers请求头字符串转为字典的方法
Aug 21 #Python
利用python在大量数据文件下删除某一行的例子
Aug 21 #Python
Python 仅获取响应头, 不获取实体的实例
Aug 21 #Python
You might like
用php写的serv-u的web申请账号的程序
2006/10/09 PHP
PHP输出时间差函数代码
2013/01/28 PHP
Yii实现自动加载类地图的方法
2015/04/01 PHP
php中文验证码实现方法
2015/06/18 PHP
WordPress开发中短代码的实现及相关函数使用技巧
2016/01/05 PHP
YII Framework框架教程之缓存用法详解
2016/03/14 PHP
用于table内容排序
2006/07/21 Javascript
href下载文件根据id取url并下载
2014/05/28 Javascript
iframe调用父页面函数示例详解
2014/07/17 Javascript
JavaScript中的Math.LOG2E属性使用详解
2015/06/14 Javascript
Angular2学习笔记——详解NgModule模块
2016/12/02 Javascript
jQuery Mobile漏洞会有跨站脚本攻击风险
2017/02/12 Javascript
NodeJs的fs读写删除移动监听
2017/04/28 NodeJs
vue+webpack 打包文件 404 页面空白的解决方法
2018/02/28 Javascript
vue-cli脚手架的安装教程图解
2018/09/02 Javascript
微信小程序MUI导航栏透明渐变功能示例(通过改变opacity实现)
2019/01/24 Javascript
vue中解决微信html5原生ios虚拟键返回不刷新问题
2020/10/20 Javascript
[53:21]2014 DOTA2国际邀请赛中国区预选赛5.21 DT VS LGD-CDEC
2014/05/22 DOTA
浅谈Python类的__getitem__和__setitem__特殊方法
2016/12/25 Python
python生成词云的实现方法(推荐)
2017/06/13 Python
python根据时间获取周数代码实例
2019/09/30 Python
python 利用已有Ner模型进行数据清洗合并代码
2019/12/24 Python
python在不同条件下的输入与输出
2020/02/13 Python
科颜氏美国官网:Kiehl’s美国
2017/01/31 全球购物
size?瑞典:英国伦敦的球鞋精品店
2018/03/01 全球购物
百度吧主申请感言
2014/01/12 职场文书
人力资源管理专业毕业生自荐书
2014/05/25 职场文书
体育比赛口号
2014/06/09 职场文书
企业公益活动策划方案
2014/08/24 职场文书
化学专业大学生职业生涯规划范文
2014/09/13 职场文书
高中生自我评价范文2015
2015/03/03 职场文书
医学生自荐信范文
2015/03/05 职场文书
保险公司客户经理岗位职责
2015/04/09 职场文书
nginx proxy_cache 缓存配置详解
2021/03/31 Servers
使用vue-element-admin框架从后端动态获取菜单功能的实现
2021/04/29 Vue.js
升级 Win11 还是坚守 Win10?微软 Win11 新系统缺失功能大盘点
2022/04/05 数码科技