详解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 统计代码行数简单实例
May 04 Python
Python爬取当当、京东、亚马逊图书信息代码实例
Dec 09 Python
python实现搜索文本文件内容脚本
Jun 22 Python
Python统计python文件中代码,注释及空白对应的行数示例【测试可用】
Jul 25 Python
详解Python的数据库操作(pymysql)
Apr 04 Python
python+django+rest框架配置创建方法
Aug 31 Python
django创建简单的页面响应实例教程
Sep 06 Python
pytorch torch.nn.AdaptiveAvgPool2d()自适应平均池化函数详解
Jan 03 Python
Python魔术方法专题
Jun 19 Python
Pycharm导入anaconda环境的教程图解
Jul 31 Python
python opencv pytesseract 验证码识别的实现
Aug 28 Python
Python3 多线程(连接池)操作MySQL插入数据
Jun 09 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
SONY SRF-22W(33W)的电路分析和维修案例
2021/03/02 无线电
PHP+ACCESS 文章管理程序代码
2010/06/21 PHP
PHP获取栏目的所有子级和孙级栏目的ID号示例
2014/04/01 PHP
PHP实现的折半查询算法示例
2017/10/09 PHP
Prototype Hash对象 学习
2009/07/19 Javascript
jquery实现div阴影效果示例代码
2013/09/16 Javascript
JavaScript设计模式之适配器模式介绍
2014/12/28 Javascript
浅谈javascript事件取消和阻止冒泡
2015/05/26 Javascript
javascript中字体浮动效果的简单实例演示
2015/11/18 Javascript
JS函数arguments数组获得实际传参数个数的实现方法
2016/05/28 Javascript
浅谈AngularJS中ng-class的使用方法
2016/11/11 Javascript
浅谈JS读取DOM对象(标签)的自定义属性
2016/11/21 Javascript
javascript监听页面刷新和页面关闭事件方法详解
2017/01/09 Javascript
老生常谈javascript中逻辑运算符&amp;&amp;和||的返回值问题
2017/04/13 Javascript
Bootstrap 模态对话框只加载一次 remote 数据的完美解决办法
2017/07/09 Javascript
webpack学习笔记之优化缓存、合并、懒加载
2017/08/24 Javascript
React Native AsyncStorage本地存储工具类
2017/10/24 Javascript
JS中图片压缩的方法小结
2017/11/14 Javascript
React+Webpack快速上手指南(小结)
2018/08/15 Javascript
详解React项目中碰到的IE问题
2019/03/14 Javascript
微信小程序地图绘制线段并且测量(实例代码)
2020/01/02 Javascript
JavaScript中继承原理与用法实例入门
2020/05/09 Javascript
原生JavaScript实现轮播图
2021/01/10 Javascript
[40:53]完美世界DOTA2联赛PWL S3 Magma vs DLG 第二场 12.18
2020/12/20 DOTA
python基础教程之lambda表达式使用方法
2014/02/12 Python
修改Python的pyxmpp2中的主循环使其提高性能
2015/04/24 Python
Python使用ftplib实现简易FTP客户端的方法
2015/06/03 Python
利用Python破解验证码实例详解
2016/12/08 Python
Python3 操作符重载方法示例
2017/11/23 Python
wxPython实现带颜色的进度条
2019/11/19 Python
如何基于windows实现python定时爬虫
2020/05/01 Python
解决echarts中饼图标签重叠的问题
2020/05/16 Python
英国最大的香水商店:The Fragrance Shop
2018/07/06 全球购物
什么是规则表达式
2012/05/03 面试题
高三毕业寄语
2014/04/10 职场文书
预备党员考察表党小组意见
2015/06/01 职场文书