Django3框架-(3)-[使用websocket]:使用channels实现websocket功能;简化的配置和实际使用方式

news2025/2/22 19:36:31

概述:

对于Django使用channels实现websocket的功能,之前就写了几篇博文了。随着在项目的使用和实际维护来说,重新设置了相关处理方法。

一般来说,前后端都只维护一个全局的连接,通过携带数据来判断具体的操作,大致的业务逻辑(非群聊功能):

1、前端主动发起连接,发送了数据给后端,后端获取到数据后,解析出前端需要的是啥数据,查询出数据,返回给前端。(一次请求一次返回了)

2、部分数据变化了,后端需要主动告知前端,让前端重新查询对应的数据。(实时更新数据)

一、依赖

python=3.9.0

包:

pip install channels==3.0.0
pip install daphne==3.0.2
pip install redis==4.6.0
pip install channels-redis=3.1.0

django-cors-headers==3.5.0

项目结构:

项目名

  • apps

    • user

    • websocket

      • routings.py

      • consumers.py

      • update.py

      • send_date.py

      • __init__.py

  • 项目名

    • settings.py

    • asgi.py

    • urls.py

    • wsgi.py

    • __init__.py

  • manage.py

二、settings.py设置

#注册channels
INSTALLED_APPS = [
   	...
    'channels',  # django通过其实现websocket
]

WSGI_APPLICATION = 'HeartFailure.wsgi.application'

#channels使用需要添加ASGI_APPLICATION
ASGI_APPLICATION = 'HeartFailure.asgi.application'

#使用channel_layers需要配置通道
CHANNEL_LAYERS = {
    "default": {
        #1、使用内存作为通道(开发使用)
        "BACKEND": "channels.layers.InMemoryChannelLayer",
        #2、使用redis(上线使用)
        # 'BACKEND': 'channels.layers.RedisChannelLayer',
        # 'CONFIG': {
        #     'hosts': [('localhost', 6379)],
        # },
    }
}

#####1、 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' #请求头允许自定义的字符串
)

三、创建websocket包

概述:将所有的wesocket相关的请求都放到一个包,集中管理。

 

websocket包下创建:

  • routings.py

    • 存放websocket请求相关的路由信息

  • consumers.py

    • 存放websocket请求处理的类

  • update.py

    • 数据变化时,服务器主动通知前端更新数据

  • send_data.py

    • 前端发起请求时,返回的数据

1、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 apps.websocket.send_data 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']
        print(headers)
        token = None
        for key, value in headers:
            if key == b'token':
                token = value.decode('utf-8')
                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': '传递的数据请按照{"type":"xx","id":x,"params":{}}格式'}, ensure_ascii=False))
            self.disconnect(400)
            return

        #1、前端主动请求websocket时,拿到对应的数据,单独给该websocket返回数据
        send_data = base_send(text_data_json)
        if isinstance(send_data,dict):
            #需要给请求的前端返回数据
            self.send(json.dumps(send_data, ensure_ascii=False))
        else:
            #无需给请求的前端返回数据
            pass

        # 2、将数据发送到房间组内 (在非聊天模式无需这样操作)
        # async_to_sync(self.channel_layer.group_send)(
        #     self.room_group_name, {'type':'send_to_chrome','data':send_data}
        # )
        '''
        参数说明:
        self.room_group, 给哪个房间组发送数据,
        {'type':'send_to_chrome','data':send_data}
            send_to_chrome 是处理函数,在这里负责将房间组内的数据发送给浏览器
            send_data  要发送的数据
        '''

    # 自定义的处理房间组内的数据:实时推送就是使用这个来实现的
    def send_to_chrome(self, event):
        try:
            data = event.get('data')
            # 接收房间组广播数据,将数据发送给websocket
            self.send(json.dumps(data, ensure_ascii=False))
        except Exception as e:
            print('给全局的websocket推送消息失败')


2、send_data.py


def base_send(data:dict):
    '''
    功能:发起websocket请求时,给当前websocket返回数据
    :param data: {'type':'要操作的数据类型','id':'有id就是指定每个数据','params':{'page':'页码','page_size':'页面大小', }}
    :return:
    '''
    the_type = data.get('type')
    id = data.get('id')
    send_data = {
        'type':the_type,
        'data':'返回的数据'
    }
    #用户管理-搜索功能,用户信息是实时更新的
    if the_type == 'search_user_data':
        #前端发起websocket请求时,此类型时,无需返回数据
        return send_data

3、update.py

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

class AllDataConsumersUpdate:
    '''
    功能:在http视图中,给房间组=chat_all_data 推送指定的消息
    '''

    def _make_channel_layer(self,send_data):
        '''
        :param send_data: 在http视图中查询好的数据,要给房间组内所有的websocket对象发送数据
        '''
        channel_layer = get_channel_layer()
        #拿到房间组名
        group_name = 'chat_all_data'
        #给该房间组组内发送数据 注意是group_send方法
        async_to_sync(channel_layer.group_send)(
            group_name, #房间组名,给这个房间组发送数据
            {
                'type':'send_to_chrome', #处理这个房间组的消费者类必须有send_to_chrome方法
                'data':send_data   #要发送给websocket对象的数据
            }
        )
        '''
        send_to_chrome: 该房间组对应的消费者,必须存在这个函数,在这个函数中进行将数据发送给房间组所有的websocket对象
        send_data : 查询出来的数据
        '''
    #用户管理-搜索用户页面-实时更新数据,由前端自己去获取数据
    def search_user_data(self):
        send_data = {
            'type':'search_user_data',
            'page_update':1
        }
        #给房间发送数据
        self._make_channel_layer(send_data=send_data)
        return True

4、routings.py

from django.urls import path
from . import consumers

# 这个变量是存放websocket的路由
socket_urlpatterns = [
    path('socket/all/',consumers.AllDataConsumers.as_asgi()),

]

四、修改settings.py同级的asgi.py文件

asgi.py

import os

from django.core.asgi import get_asgi_application

#新的模块
from channels.routing import ProtocolTypeRouter, URLRouter
# 导入websocket的路由模块
from apps.websocket import routings

#项目名,settings.py所在的目录名
os.environ.setdefault('DJANGO_SETTINGS_MODULE', '项目名.settings')

application = ProtocolTypeRouter({
    # http路由走这里
    "http": get_asgi_application(),
    # chat应用下rountings模块下的路由变量socket_urlpatterns,就是存路由的列表
    "websocket": URLRouter(routings.socket_urlpatterns)
})

五、在视图函数中怎么发送websocket通知

from apps.websocket.update import websocket_update_obj #websocket推送数据的接口

#在视图函数中直接调用需要的方法就可以实现推送了
websocket_update_obj.search_user_data()

将所有的推送方法都放到一个类中,可以很方便的进行管理,后期修改时,也可以实现统一的修改。

六、启动项目

python manage.py runserver 8005

看到 ASGI/Channels Version xxx 就说明启动成功,此时的django项目才支持websocket

七、测试

访问:EasySwoole-WebSocket在线测试工具

  • 1、服务地址:http://127.0.0.1:8005/socket/all/

  • 2、点击连接

  • 3、发送数据:{"type":"search_user_data"}

  • 4、点击发送

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

京东协议算法最新版

环境准备 1 com.jingdong.app.mall11.6.4 入口定位 逆向分析,发现 params 里面有一个 sign 以及请求头里面有一个 jdgs 首先我们发现京东的 sign 是 32 位的,猜测其可能是 md5 之类的 hash 算法,既然是 hash 算法,那么就大概率…

程序员不得不知道的三大编程语言,看看你了解吗?

作为一名合格的程序员,不仅要有过硬的技术,还要了解许多基础知识。编程语言可是程序员工作的主力军,但是它是如何产生和发展的,你知道吗?接下来就让我们一起来看看编程语言和它们的发展吧!记得点赞加收藏哦…

对 Webpack 的理解

结论先行: Webpack 是目前比较常用的模块打包工具,它能够管理和打包我们开发中所用到的 HTML、 CSS、JS 以及各种静态资源文件。 webpack内部做的事情呢,就是分析出各个模块之间的依赖关系,然后形成资源列表,最终打包…

FL Studio21.2.0.3842中文免费版和谐绿色版本下载

FL Studio21.2.0.3842中文免费版带有 stem 分离和 FL Cloud,这是一项专为 FL Studio 打造的具有里程碑意义的新服务。其他新功能包括 FL Studio Fruity Edition 的 Audio Clips(音频剪辑)和一个新的模拟建模合成器 Kepler。 为庆祝 FL Studio…

python类如何实例化对象

python类如何实例化对象 1、把类看作是定制的数据类型。既然是类型,只能用来表示数据的类型,不能直接用来保存数据。**要保存数据,首先需要创建一个类似于这类容器的东西,称为对象(或例子)。通过类别产生对象的过程称为例子。 2、…

Windows新建计划任务定时执行脚本

右键-此电脑,选择管理 点击 - 任务计划程序, 选择- 创建基本任务 输入任务描述,点击下一步 选择计划任务周期, 每天/每周等,点击下一步 选择每天任务执行时间,然后点击下一步, 选择启动程序&…

javaEE -15( 13000字 JavaScript入门 - 2)

一:JavaScript(WebAPI) JS 分成三个大的部分 ECMAScript: 基础语法部分DOM API: 操作页面结构BOM API: 操作浏览器 WebAPI 就包含了 DOM BOM,这个是 W3C 组织规定的. (和制定 ECMAScript 标准的大佬们不是一伙人). 前面学的 JS 基础语法主要学的是 …

百度智能云千帆大模型平台黑客马拉松报名开启!

比赛简介 创造是生成式 AI 的核心。无论是智能导购带来的线上购物体验升级,还是主图生成带来的素材生产效率提升,又或是游戏场景的快速设置、智能 NPC 的全新交互、数字广告的精准推荐和个性化定制,亦或者是为学生提供更符合真实的口语练习环…

《高性能MySQL-第三版》学习笔记一

第1章 MySQL架构与历史 1.1 MySQL逻辑架构 表现层:是应用程序的用户界面(UI)部分,大多数基于网络的客户端/服务器的工具或者服务都有类似的架构。比如连接处理、授权认证、安全等等。逻辑层:查询解析、分析、优化、缓…

王道p18 2.设计一个高效算法,将顺序表L的所有元素逆置,要求算法的空间复杂度为 O(1)。(c语言代码实现)

视频讲解在这&#xff08;支持一下吧&#xff0c;谢谢各位大佬&#xff09;&#xff1a;&#x1f447; c语言代码实现数据结构课后代码题顺序表p18 2_哔哩哔哩_bilibili 本题代码如下 void nizhi(struct sqlist* s) {int temp 0;for (int i 0; i < s->length / 2; i…

第三届iEnglish全国ETP大赛决赛即将启动

如今,寓教于乐的学习方式越来越受到家长和孩子的欢迎,“玩中学”成为一种既能培养兴趣又有助于孩子成长的学习趋势。 以“玩转英语,用iEnglish”为活动主题的第三届全国ETP大赛即将于本周五(11月3日)迎来总决赛的抽签仪式。据主办方iEnglish智能英语学习解决方案相关负责人称,…

如何卸载干净 IDEA(图文讲解)windows和Mac教程

大家好&#xff0c;我是sun~ 很多小伙伴会问 Windows / Mac 系统上要怎么彻底卸载 IDEA 呢&#xff1f; 本文通过图片文字&#xff0c;详细讲解具体步骤&#xff1a; 如何卸载干净 IDEA&#xff08;图文讲解&#xff09; Windows1、卸载 IDEA 程序2、注册表清理3、残留清理 M…

操作系统第四章-存储器管理

4.1 内存的基本知识 4.1.1 逻辑地址和物理地址 逻辑地址又称为相对地址 物理地址又称为绝对地址 一. 逻辑地址 内存中有多个进程,相对地址是相对于进程的起始地址而言的地址. 二.物理地址 绝对地址是在整个内存下的地址 4.2 程序的装入和链接 引入:用户程序要在系统中运…

什么是智慧燃气,智慧燃气解析干货!

关键词&#xff1a;智慧燃气、智慧燃气系统、智慧燃气平台、智能燃气、燃气智能管网、数据挖掘 在互联网技术、无线通信技术、物联网技术、卫星通信技术、大数据、云计算技术飞速发展的今天&#xff0c;业界提出了“智慧城市”的概念。智慧城市的范围很广&#xff0c;包含智慧…

Flask 网站装潢, 简易更换模板

Flask 网站装潢&#xff0c;简易更换模板 本博文找个好看的网页模板&#xff0c;并简单改一改变成flask模板&#xff0c;并展示 主博客目录&#xff1a;《从零开始学习搭建量化平台笔记》 文章目录 Flask 网站装潢&#xff0c;简易更换模板下载模板Python 自动生成目录修改目录…

@reduxjs/toolkit配置react-redux解决createStore或将在未来被淘汰警告

通常 我们用redux都需要通过 createStore 但目前 你去用它 基本都会被划线 甚至有点厉害的的编辑器 他会直接告诉你这个东西基本快被弃用了 这个应该大家都知道 最好不要用已经被明确未来或弃用的语法 因为一旦弃用这个系统就需要维护 而且说 一般会被淘汰的语法 本身也就是有…

编程怎么学才高效?初学编程怎么样才容易入门?

学习编程并提高编程能力需要一种结构化的方法&#xff0c;其中包括理解基础概念、实践、反馈和持续学习。以下是一些高效学习编程的策略&#xff1a; 理解基础概念&#xff1a;在学习编程的初期&#xff0c;理解基础概念非常重要。这包括学习编程语言的基本语法、数据类型、控…

嵌入式与单片机之间的关系是什么?

今日话题&#xff0c;嵌入式与单片机之间的关系是什么&#xff1f;可以这样理解&#xff1a;嵌入式系统是一个大的范畴&#xff0c;而单片机则是嵌入式系统中的一个重要子类。通常情况下&#xff0c;制造商出厂的通用单片机内并没有预装应用程序&#xff0c;因此无法直接运行。…

799. 最长连续不重复子序列 java

目录 算法描述 输入格式 输出格式 数据范围 输入样例&#xff1a; 输出样例&#xff1a; 代码 算法分析 算法描述 给定一个长度为 n&#xfffd; 的整数序列&#xff0c;请找出最长的不包含重复的数的连续区间&#xff0c;输出它的长度。 输入格式 第一行包含整数 n&…

成集云 | 英克ERP对接批发销售门店 | 解决方案

方案介绍 批发连锁门店是一种以批发销售为主&#xff0c;通过连锁经营方式进行管理的商业组织形态。它通常由一个总店或总公司负责管理和运营&#xff0c;下面拥有多个分店或加盟店&#xff0c;形成一个连锁经营网络。主要业务是向下游零售商或消费者销售商品&#xff0c;因此…