Django框架:使用channels实现websocket,配置和项目实际使用

一、基本配置

依赖包:

Django==3.2
django-cors-headers==3.5.0
redis==4.6.0  #操作redis数据库的
channels==3.0.0  #websocket
channels-redis==4.1.0 #通道层需要,依赖redis包

项目目录结构:

study_websocket

        --study_websocket

                --__init__.py

                --settings.py

                --asgi.py

                --wsgi.py

                --urls.py

        --chat

                --routings.py

                --consumers.py

                --update.py

                --urls.py

                --views.py

1.1、settings.py配置

1、注册跨域、channels、chat应用

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'corsheaders', #前后端跨域

    'chat.apps.WebsocketConfig',#专门用于写websocket的方法
    'channels', #django通过其实现websocket
]

 

2、跨域配置

##### cors资源跨域共享配置
CORS_ORIGIN_ALLOW_ALL = True
CORS_ALLOW_METHODS = (
    'DELETE',
    'GET',
    'OPTIONS',
    'PATCH',
    'POST',
    'PUT',
    'VIEW',
)

CORS_ALLOW_HEADERS = (
    'XMLHttpRequest',
    'X_FILENAME',
    'accept-encoding',
    'authorization',
    'content-type',
    'dnt',
    'origin',
    'user-agent',
    'x-csrftoken',
    'x-requested-with',
    'Pragma',
    'token' #请求头允许自定义的字符串
)

    3、channels需要的配置

WSGI_APPLICATION = 'study_websocket.wsgi.application'
#channels使用需要添加ASGI_APPLICATION
ASGI_APPLICATION = 'study_websocket.asgi.application'
#通道层:开发阶段使用内存
CHANNEL_LAYERS = {
    "default": {
        "BACKEND": "channels.layers.InMemoryChannelLayer"
    }
}

1.2、在chat应用新增routings.py 和 consumers.py

1、consumers.py设置一个简单消费者

from channels.generic.websocket import WebsocketConsumer
from channels.exceptions import StopConsumer
from asgiref.sync import async_to_sync
import time
 
class ChatView(WebsocketConsumer):
    def websocket_connect(self, message):
        #客户端与服务端进行握手时,会触发这个方法
        #服务端允许客户端进行连接,就是握手成功
        self.accept()
 
    def websocket_receive(self, message):
        #接收到客户端发送的数据
        recv = message.get('text')
        print('接收到的数据,',recv)
        if recv == 'close':
            #服务的主动断开连接
            print('服务器断开连接')
            self.close()
        else:
            #客户端向服务端发送数据
            self.send(f'我收到了,{time.strftime("%Y-%m-%d %H:%M:%S")}')
 
    def websocket_disconnect(self, message):
        #客户端端口连接时,会触发该方法,断开连接
        print('客户端断开连接')
        raise StopConsumer()

2、配置routings.py

from django.urls import path
from . import consumers
 
#这个变量是存放websocket的路由
socket_urlpatterns = [
    path('chat/socket/',consumers.ChatView.as_asgi()),
]

1.3、修改跟settings.py同级目录下的asgi.py

import os
from django.core.asgi import get_asgi_application
from channels.routing import ProtocolTypeRouter,URLRouter
#导入chat应用中的路由模块
from chat import routings
 
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'study_websocket.settings')
application = ProtocolTypeRouter({
    #http路由走这里
    "http":get_asgi_application(),
    #chat应用下rountings模块下的路由变量socket_urlpatterns
    "websocket":URLRouter(routings.socket_urlpatterns)
})

1.4、启动项目

启动命令:python manage.py runserver 8888

启动提示:如下就是配置成功了

 

在线测试websocket的网站:

EasySwoole-WebSocket在线测试工具EasySwoole在线WebSocket测试工具icon-default.png?t=N6B9http://www.easyswoole.com/wstool.html

服务地址:ws://127.0.0.1:8888/chat/socket/  点击开启连接

连接成功后,就可以向服务端发送数据了。

二、房间组使用(聊天室:待更新)

三、房间组使用(非聊天室)

 概述:

data = {'type':'xxx'}

1、前端只想维护一个全局的websocket对象,通过发送的数据中type的不同获取到不同的数据。

2、在后端给前端主动推送数据时,也是通过这个type来确定要重新渲染的数据。

构建想法:

1、设置一个处理全局websocket的消费者类

2、设置一个全局websocket都进入的房间组

3、在chat应用下新建一个update.py: websocket返回数据 和主动推送数据都放到这个模块中

consumers.py

from channels.generic.websocket import WebsocketConsumer
from channels.exceptions import StopConsumer
from asgiref.sync import async_to_sync
import time
import json

#接收到websocket请求,直接向单个发送需要数据
from websocket.update import base_send

class AllDataConsumers(WebsocketConsumer):
    #统一的房间名
    room_name = 'chat_all_data'
    def connect(self):
        cls = AllDataConsumers
        self.room_group_name = cls.room_name
        #加入到房间组内, self.channel_name是当前
        async_to_sync(self.channel_layer.group_add)(
            self.room_group_name, self.channel_name
        )
        headers = self.scope['headers']
        token = None
        for key,value in headers:
            if key == b'token':
                token = value.decode('utf-8')
        if token:
            print(token)
        else:
            print('没有token数据')

        self.accept()

    def disconnect(self, close_code):
        print('有浏览器退出了websocket!!!!')
        # Leave room group
        async_to_sync(self.channel_layer.group_discard)(
            self.room_group_name, self.channel_name
        )

    # Receive message from WebSocket
    def receive(self, text_data=None, bytes_data=None):
        '''
        :param text_data: 接收字符串类型的数据
        :param bytes_data:  接收bytes类型的数据
        :return:
        如果是浏览器直接请求时,就单独给这个浏览器返回结果,无需给房间组内的发送数据
        '''
        try:
            text_data_json = json.loads(text_data)
            the_type = text_data_json.get('type','none')
        except Exception as e:
            self.send(json.dumps({'code':400,'msg':'传递的数据有问题'},ensure_ascii=False))
            self.disconnect(400)
            return
        #个人信息:所有的老人信息
        if the_type == 'all_patient_page_data':
            send_data = base_send(text_data_json)
            self.send(json.dumps(send_data,ensure_ascii=False))
        #来访登记:进行中的来访登记
        if the_type == 'all_active_visit_data':
            send_data = base_send(text_data_json)
            self.send(json.dumps(send_data,ensure_ascii=False))


    #自定义的处理房间组内的数据
    def send_to_chrome(self, event):
        try:
            data = event.get('data')
            #接收房间组广播数据,将数据发送给websocket
            self.send(json.dumps(data,ensure_ascii=False))
        except Exception as e:
            error_logger.exception(str(e),'给全局的websocket推送消息失败')


update.py

import json
from datetime import datetime,timedelta
from django.db.models import Q

#channels包相关
from asgiref.sync import async_to_sync
from channels.layers import get_channel_layer


def base_send(data:dict):
    '''
    功能:发起websocket请求时,给当前websocket返回查询到的数据
    '''
    the_type = data.get('type')
    id = data.get('id')
    send_data = {
        'type':the_type,
    }
    #个人管理-首次进入时,没有点击搜索时,这个需要实时获取
    if the_type == 'all_patient_page_data':
        
        send_data['data'] = '数据库查询到的数据:个人管理'
        return send_data

    #来访登记:进行中的来访记录
    if the_type == 'all_active_visit_data':
        send_data['data'] = '数据库查询到的数据:来访记录'
        return send_data

    #


class AllDataConsumersUpdate:
    '''
    功能:在http视图中,给房间组=chat_all_data 推送指定的消息
        在视图函数中,某些数据更新了,需要通知所有的websocket对象
    '''

    def _make_channel_layer(self,send_data):
        '''
        :param send_data: 在http视图中查询好的数据,要给房间组内所有的websocket对象发送数据
        '''
        channel_layer = get_channel_layer()
        #拿到房间组名
        group_name = 'chat_all_data'
        #给该房间组组内发送数据
        async_to_sync(channel_layer.group_send)(
            group_name,
            {
                'type':'send_to_chrome', #消费者中处理的函数
                'data':send_data
            }
        )

    #个人信息:
    def all_patient_page_data(self):
       
        try:
            send_data = {
                'type':'all_patient_page_data',
                'data':'更新数据了,个人信息'
            }
            #把更新的数据发送到房间组内
            self._make_channel_layer(send_data=send_data) 
          
        except Exception as e:
            pass

    #来访登记:
    def all_active_visit_data(self):
        try:
            send_data = {
                'type':'all_patient_page_data',
                'data':'更新数据了,来访登记'
            }
            #把更新的数据发送到房间组内
            self._make_channel_layer(send_data=send_data) 
        except Exception as e:
            error_logger.exception(str(e))

rountings.py

from django.urls import path
from . import consumers
 
#这个变量是存放websocket的路由
socket_urlpatterns = [
    path('chat/socket/',consumers.ChatView.as_asgi()),
    path('socket/all/',consumers.AllDataConsumers.as_asgi()),
]
 

两个视图函数

from chat.update import AllDataConsumersUpdate
#2023-07-25:模拟来访记录变化
update = AllDataConsumersUpdate()
update.all_active_visit_data()

from chat.update import AllDataConsumersUpdate

#2023-07-25:模拟个人信息编变化
update = AllDataConsumersUpdate()
update.all_patient_page_data()

 

1、先使用测试网站连接上:

EasySwoole-WebSocket在线测试工具

2、再访问写的两个视图函数,看websocket是否返回数据

业务逻辑:

1、创建连接时,把websocket对象放到同一个房间组内

2、当是websocket对象主动给后端发送数据时,后端只对这个websocket对象返回数据

3、当在视图中调用主动推送的方法,

        a.把数据发送到房间组内

        b.通过设置好的处理方法send_to_chrome 来实现从房间组内拿到数据,发送给websocket对象

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/45426.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

redis 第一章

目录 1.redis 安装部署 2.redis 数据库常用命令 3.总结 1.redis 安装部署 2.redis 数据库常用命令 3.总结 redis(远程字典服务器)是一个开源的、使用 C 语言编写的 nosql 数据库。redis 基于内存运行并支持持久化,采用 key-value&#xff0…

华为战略方法论:BLM模型之关键任务与依赖关系

内容简介 在 BLM 模型中,执行部分包括四个模块,分别是: 关键任务与依赖关系;组织与绩效;人才;氛围与文化。 详细内容,大家可以参看下面这张图。 这四个模块其实是可以进一步划分成两个关键点…

JavaWeb开发(后端Web开发【一】)

文章目录 前言一、Maven1.Maven概述-介绍1.1.Maven概述-介绍1.2.Maven概述-安装 2.IDEA集成Maven2.1.IDEA集成Maven-配置Maven环境2.2.IDEA集成Maven-创建Maven项目2.3.IDEA集成Maven-导入Maven项目 3.Maven-依赖管理3.1.Maven-依赖管理-依赖配置3.2.Maven-依赖管理-依赖传递3.…

九五从零开始的运维之路(其二十五)

文章目录 前言一、概述二、配置环境及搭建服务1.关闭防火墙、网络图形化工具及SElinux2.配置yum源3.测试网络连通性4.分配磁盘容量5.安装targetcli包6.服务器端进行配置7.客户端 总结 前言 本篇将简述的内容:Linux系统下的ISCSI服务 一、概述 iscsi全称&#xff1…

笔试题:统计字符串中某字符串在其出现的字符个数

笔试题:统计字符串中某一子串的字符个数:例如字符串aabbcd,有aabb:4,ab:2 哈哈,这道题是小编面试音视频龙头企业的笔试题,以下是我写的代码:如果有错误,希望可以指正!!! 解题思路:利用双指针i和…

synchronized 关键字

目录 背景过程历史概念实际应用方法1:放方法名前形成同步方法;方法2:使用同步块修改上面的例子; 应用方法锁住对象:锁住类: 总结 背景 学习并发,为解决并发带来的问题,引入synchron…

React Dva项目中模仿网络请求数据方法

我们都已经选择react了 那么自然是一个前后端分离的开发形式 至少我在公司中 大部分时候是前后端同时开发的 一般你在开发界面没有接口直接给你 但你可以和后端约定数据格式 然后在前端模拟数据 我们在自己的Dva项目中 在根目录下的 mock 目录下创建一个js文件 我这里叫 filmDa…

ES6 (js)

学习了很多vue的视频,还有nuxt的,还是不会。 还是要学ES6 本文的大部分出自小马老师的资料,还有曾大佬的文章 变量(Let 和 const) 在es6中,多用let 和const 来声明变量类型。因为var 会提前声明&#xff0…

flink cdc环境搭建

1.下载flink https://archive.apache.org/dist/flink/flink-1.12.2/ 2.修改flink-conf.yaml #根据自己电脑核数修改,这里我设置为4,因为系统分配了4核 jobmanager.rpc.address: localhost #主机名根据自己设定 taskmanager.numberOfTaskSlots: 4 3.下载…

mysql进阶2——prosysql实现mysql读写分离

文章目录 一、读写分离方案类型1.1 最简单的读写分离1.2 多个读组或写组的分离模式 二、案例2.1 初始化操作2.2 mysql主添加proxysql连接用户2.3 Proxysql添加连接mysql集群参数2.4 添加健康检测用户2.5 添加读写分离的路由规则2.6 验证 一、读写分离方案类型 基本了解&#xf…

【uniapp】更改富文本编辑器图片大小

代码块 //<view v-html"productDetails"></view><rich-text :nodes"productDetails"></rich-text>// 假设htmlContent字段是后台返回的富文本字段var htmlContent res.result.productDetailsconst regex new RegExp(<img, gi…

STM32MP157驱动开发——按键驱动(休眠与唤醒)

文章目录 “休眠-唤醒”机制&#xff1a;APP执行过程内核函数休眠函数唤醒函数 休眠与唤醒方式的按键驱动程序(stm32mp157)驱动程序框架button_test.cgpio_key_drv.cMakefile修改设备树文件编译测试 “休眠-唤醒”机制&#xff1a; 当应用程序必须等待某个事件发生&#xff0c…

爬虫001_Pip指令使用_包管理工具_pip的使用_和源的切换---python工作笔记019

scrapy是一个爬虫的框架 确认一下pip这个python中的包管理工具是否已经安装好了 python的环境变量配置完了以后,还需要配置一下pip的环境变量 把这个目录配置好,这个pip的环境变量的配置很简单不多说了. 我们用pip安装一下包,我们安装到上面这个路径里面,就是python的安装路…

Qt - .ui 文件的使用

文章目录 目录工具栏Dock Widget代码控制 ui添加资源添加文件 目录 子目录只能输入英文&#xff0c;想要显示中文&#xff0c;可以修改右下方表中的 text 属性&#xff1a; 工具栏 让工具栏共用 菜单栏的 new 和 open&#xff0c;只需将下方列表的控件&#xff0c;拖拽到工具栏…

【RS】基于规则的面向对象分类

ENVI使用最多的工具就是分类&#xff0c;这也是很多卫星影像的用途。在ENVI中有很多分类工具&#xff0c;如最基础的监督分类&#xff08;最大似然法、最小距离、支持向量机、随机森林&#xff09;、非监督分类&#xff08;K-means、IsoData&#xff09;&#xff0c;还有面向对…

安卓开发后台应用周期循环获取位置信息上报服务器

问题背景 最近有需求&#xff0c;在APP启动后&#xff0c;退到后台&#xff0c;还要能实现周期获取位置信息上报服务器&#xff0c;研究了一下实现方案。 问题分析 一、APP退到后台后网络请求实现 APP退到后台后&#xff0c;实现周期循环发送网络请求。目前尝试了两种方案是…

随笔--更改已经启动中的容器的配置文件

文章目录 docker 容器的配置信息地址修改文件映射 docker 容器的配置信息地址 # 一般在 sudo su cd /cd /var/lib/docker/containers/{容器id}/ # 查看容器的id,CONTAINER ID就是容器id的前部分 docker ps修改文件映射 进入容器的配置文件位置一般包含这些文件 # 先stop容器…

Docker--harbor私有仓库部署与管理

目录 一、构建私有库 1.下载 registry 镜像 2.在 daemon.json 文件中添加私有镜像仓库地址 3.运行 registry 容器 4.为镜像打标签 5.上传到私有仓库 6.列出私有仓库的所有镜像 7.列出私有仓库的centos镜像有哪些tag 8.测试私有仓库下载 二、Harbor 简介 1.什么是Harb…

iOS--属性关键字

定义 chat&#xff1a; 在iOS开发中&#xff0c;属性关键字是用于声明类的属性&#xff08;实例变量&#xff09;的修饰符。属性关键字可以影响属性的访问权限、内存管理和生成相关的getter和setter方法。 属性关键字有哪些&#xff1f; 分类属性关键字原子性atomic、nonato…

Spring MVC-基础概念(定义+创建和连接+@RequestMappring的描述)

目录 1.什么是Spring MVC&#xff1f; 2. MVC 和 Spring MVC 的关系 3.Spring MVC 项目创建 4. RequestMappring实现用户和程序的映射 4.1 RequestMappring 注解解释 4.2 方法1: RequestMapping(“/xxx”) 4.4 RequestMapping(method xxxx, value “xxx”) 是POST/GET…