详解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中单例模式总结
Feb 20 Python
python模块导入的方法
Oct 24 Python
python实现把两个二维array叠加成三维array示例
Nov 29 Python
详解opencv中画圆circle函数和椭圆ellipse函数
Dec 27 Python
使用pytorch实现可视化中间层的结果
Dec 30 Python
python实现贪吃蛇游戏源码
Mar 21 Python
基于python爬取有道翻译过程图解
Mar 31 Python
Django ORM实现按天获取数据去重求和例子
May 18 Python
用opencv给图片换背景色的示例代码
Jul 08 Python
python openCV自制绘画板
Oct 27 Python
python连接mongodb数据库操作数据示例
Nov 30 Python
解决pytorch 保存模型遇到的问题
Mar 03 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侧拉菜单 漂亮,可以向右或者向左展开,支持FF,IE
2009/10/15 PHP
通用PHP动态生成静态HTML网页的代码
2010/03/04 PHP
Apache 配置详解(最好的APACHE配置教程)
2010/07/04 PHP
学习php分页代码实例
2013/10/24 PHP
PHP框架Laravel插件Pagination实现自定义分页
2020/04/22 PHP
PHP实现微信申请退款功能
2018/10/01 PHP
使用堆实现Top K算法(JS实现)
2015/12/25 Javascript
浅析JavaScript中的对象类型Object
2016/05/26 Javascript
全面解析Bootstrap中form、navbar的使用方法
2016/05/30 Javascript
原生js图片轮播效果实现代码
2016/10/19 Javascript
AngularJS入门教程之与服务器(Ajax)交互操作示例【附完整demo源码下载】
2016/11/02 Javascript
概述一个页面从输入URL到页面加载完的过程
2016/12/16 Javascript
windows 下安装nodejs 环境变量设置
2017/02/02 NodeJs
微信小程序中button组件的边框设置的实例详解
2017/09/27 Javascript
webpack打包js文件及部署的实现方法
2017/12/18 Javascript
vue服务端渲染页面缓存和组件缓存的实例详解
2018/09/18 Javascript
JS实现简单的文字无缝上下滚动功能示例
2019/06/22 Javascript
Vue页面刷新记住页面状态的实现
2019/12/27 Javascript
详解jQuery中的prop()使用方法
2020/01/05 jQuery
JavaScript实现简单的计算器
2020/01/16 Javascript
vue 动态给每个页面添加title、关键词和描述的方法
2020/08/28 Javascript
Ant Design moment对象和字符串之间的相互转化教程
2020/10/27 Javascript
swiperjs实现导航与tab页的联动
2020/12/13 Javascript
[03:01]2014DOTA2国际邀请赛 DC:我是核弹粉,为Burning和国土祝福
2014/07/13 DOTA
[02:45]2016年中国刀塔全程回顾,完美“圣”典即将上演
2016/12/15 DOTA
Python实现将Excel转换为json的方法示例
2017/08/05 Python
通过Python 接口使用OpenCV的方法
2018/04/02 Python
pybind11在Windows下的使用教程
2019/07/04 Python
在python plt图表中文字大小调节的方法
2019/07/08 Python
python3 实现爬取TOP500的音乐信息并存储到mongoDB数据库中
2019/08/24 Python
python+opencv实现车牌定位功能(实例代码)
2019/12/24 Python
Pyqt助手安装PyQt5帮助文档过程图解
2020/11/20 Python
财务会计专业应届毕业生求职信
2013/10/18 职场文书
运动会跳远广播稿
2014/02/04 职场文书
网聊搭讪开场白
2015/05/28 职场文书
2016年暑期见闻作文
2015/11/25 职场文书