详解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 29 Python
Python利用pyHook实现监听用户鼠标与键盘事件
Aug 21 Python
Python中optionParser模块的使用方法实例教程
Aug 29 Python
python按照多个字符对字符串进行分割的方法
Mar 17 Python
详解Python的collections模块中的deque双端队列结构
Jul 07 Python
Pycharm远程调试openstack的方法
Nov 21 Python
对python中使用requests模块参数编码的不同处理方法
May 18 Python
Python中的几种矩阵乘法(小结)
Jul 10 Python
Django 对象关系映射(ORM)源码详解
Aug 06 Python
Python3操作Excel文件(读写)的简单实例
Sep 02 Python
利用OpenCV和Python实现查找图片差异
Dec 19 Python
Django Model层F,Q对象和聚合函数原理解析
Nov 12 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
apache和php之间协同工作的配置经验分享
2013/04/08 PHP
PHP读取大文件的多种方法介绍
2016/04/04 PHP
PHP pear安装配置教程
2016/05/14 PHP
如何使用PHP给图片加水印
2016/10/12 PHP
thinkPHP5.0框架整体架构总览【应用,模块,MVC,驱动,行为,命名空间等】
2017/03/25 PHP
javascript使用for循环批量注册的事件不能正确获取索引值的解决方法
2014/12/20 Javascript
jQuery如何获取动态添加的元素
2016/06/24 Javascript
基于jQuery.validate及Bootstrap的tooltip开发气泡样式的表单校验组件思路详解
2016/07/18 Javascript
原生js实现无限循环轮播图效果
2017/01/20 Javascript
angular-ngSanitize模块-$sanitize服务详解
2017/06/13 Javascript
JS 中document.write()的用法和清空的原因浅析
2017/12/04 Javascript
js实现微信/QQ直接跳转到支付宝APP打开口令领红包功能
2018/01/09 Javascript
react.js组件实现拖拽复制和可排序的示例代码
2018/08/20 Javascript
jQuery模仿ToDoList实现简单的待办事项列表
2019/12/30 jQuery
[01:46]DOTA2上海特锦赛小组赛英文解说KotlGuy采访
2016/02/27 DOTA
利用Python绘制数据的瀑布图的教程
2015/04/07 Python
Python中利用sqrt()方法进行平方根计算的教程
2015/05/15 Python
详解Django中的ifequal和ifnotequal标签使用
2015/07/16 Python
python获取list下标及其值的简单方法
2016/09/12 Python
python 容器总结整理
2017/04/04 Python
浅析Git版本控制器使用
2017/12/10 Python
对python的文件内注释 help注释方法
2018/05/23 Python
python 文本单词提取和词频统计的实例
2018/12/22 Python
Tensorflow tf.dynamic_partition矩阵拆分示例(Python3)
2020/02/07 Python
Python 改变数组类型为uint8的实现
2020/04/09 Python
AmazeUI 网格的实现示例
2020/08/13 HTML / CSS
成人大专自我鉴定范文
2013/10/19 职场文书
水电工岗位职责
2014/02/12 职场文书
保护环境建议书400字
2014/05/13 职场文书
优秀语文教师事迹
2014/05/18 职场文书
党的群众路线批评与自我批评范文
2014/10/16 职场文书
2014年学校教学工作总结
2014/12/06 职场文书
刑事附带民事代理词
2015/05/25 职场文书
职场干货:简历中的自我评价应该这样写!
2019/05/06 职场文书
Nginx四层负载均衡的配置指南
2021/06/11 Servers
解决IIS7下无法绑定https主机的问题
2022/04/29 Servers