详解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 19 Python
Python中logging模块的用法实例
Sep 29 Python
由Python运算π的值深入Python中科学计算的实现
Apr 17 Python
python 查找字符串是否存在实例详解
Jan 20 Python
pip安装时ReadTimeoutError的解决方法
Jun 12 Python
Python 读取某个目录下所有的文件实例
Jun 23 Python
Python docx库用法示例分析
Feb 16 Python
Python Django框架实现应用添加logging日志操作示例
May 17 Python
使用python打印十行杨辉三角过程详解
Jul 10 Python
PyCharm设置Ipython交互环境和宏快捷键进行数据分析图文详解
Apr 23 Python
详解Python 中的 defaultdict 数据类型
Feb 22 Python
使用numpy nonzero 找出非0元素
May 14 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
无限级别菜单的实现
2006/10/09 PHP
三种php连接access数据库方法
2013/11/11 PHP
ThinkPHP连接数据库及主从数据库的设置教程
2014/08/22 PHP
javascript some()函数用法详解
2014/11/13 PHP
Thinkphp5+uploadify实现的文件上传功能示例
2018/05/26 PHP
php微信开发之谷歌测距
2018/06/14 PHP
修改Laravel自带的认证系统的User类的命名空间的步骤
2019/10/15 PHP
如何使用jquery控制CSS样式,并且取消Css样式(如背景色,有实例)
2013/07/09 Javascript
Jquery 改变radio/checkbox选中状态,获取选中的值(示例代码)
2013/12/12 Javascript
javascript实现简单的Map示例介绍
2013/12/23 Javascript
详解Bootstrap四种图片样式
2016/01/04 Javascript
Bootstrap进度条组件知识详解
2016/05/01 Javascript
全面了解构造函数继承关键apply call
2016/07/26 Javascript
js添加千分位的实现代码(超简单)
2016/08/01 Javascript
jquery validation验证表单插件
2017/01/07 Javascript
canvas的神奇用法
2017/02/03 Javascript
node.js中使用Export和Import的方法
2017/09/18 Javascript
js 显示日期时间的实例(时间过一秒加1)
2017/10/25 Javascript
nodeJS服务器的创建和重新启动的实现方法
2018/05/12 NodeJs
Python3安装Pymongo详细步骤
2017/05/26 Python
python导入csv文件出现SyntaxError问题分析
2017/12/15 Python
python如何压缩新文件到已有ZIP文件
2018/03/14 Python
python版opencv摄像头人脸实时检测方法
2018/08/03 Python
Python使用pandas对数据进行差分运算的方法
2018/12/22 Python
Python实现查找字符串数组最长公共前缀示例
2019/03/27 Python
python 将字符串完成特定的向右移动方法
2019/06/11 Python
Pandas之ReIndex重新索引的实现
2019/06/25 Python
python读取dicom图像示例(SimpleITK和dicom包实现)
2020/01/16 Python
CSS3 Media Queries(响应式布局可以让你定制不同的分辨率和设备)
2013/06/06 HTML / CSS
html svg生成环形进度条的实现方法
2019/09/23 HTML / CSS
管理失职检讨书
2014/02/12 职场文书
2014年机关作风建设工作总结
2014/10/23 职场文书
会计工作自我鉴定范文
2019/06/21 职场文书
新手入门Mysql--sql执行过程
2021/06/20 MySQL
Matplotlib绘制条形图的方法你知道吗
2022/03/21 Python
Spring Bean是如何初始化的详解
2022/03/22 Java/Android