Django-WebSocket-Channels项目使用

Django-WebSocket-Channels项目使用

一、简述:django实现websocket

之前django-websocket退出到3.0之后,被废弃。官方推荐大家使用channels。

channels通过升级http协议 升级到websocket协议。保证实时通讯。也就是说,我们完全可以用channels实现我们的即时通讯。而不是使用长轮询和计时器方式来保证伪实时通讯。

他通过改造django框架,使django既支持http协议又支持websocket协议。

配置环境

Python3.8.6版本

Django==2.2.16
channels==3.0.4
channels_redis==4.0.0

项目结构目录


C:.
├─application
	asgi.py  001文件 
	urls.py  002文件
	settings.py  003文件
├─apps
│  └─web
│      ├─dclient
│      │  ├─views
			 notice_view.py  	004文件
		  apps.py     			005文件
		  router.py   			006文件
		  urls.py  				007文件
		  view.py   			008文件
└─conf
1.asgi 001文件
"""
ASGI config for django_poll project.

It exposes the ASGI callable as a module-level variable named ``application``.

For more information on this file, see
https://docs.djangoproject.com/en/4.1/howto/deployment/asgi/
"""

import os

from channels.http import AsgiHandler
from channels.routing import ProtocolTypeRouter, URLRouter

from apps.web.dclient.urls import urlpatterns
from apps.web.op_drf.channelsmiddleware import QueryAuthMiddleware

os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'django_poll.settings')

application = ProtocolTypeRouter(
    {
        "http": AsgiHandler(),  # http走Django默认的asgi
        # "websocket": URLRouter(urlpatterns),         # websocket走channels
        "websocket": QueryAuthMiddleware(URLRouter(urlpatterns)),         # websocket走channels
        # "websocket": WsTokenVerify(URLRouter(urlpatterns)),

    }
)

2.urls 002文件
urlpatterns = [
	...
    re_path(r'^dclient/', include('apps.web.dclient.router')),

]

3.settings 003文件

INSTALLED_APPS = [
    "channels",  # 需要添加这个
]

# 文件最后添加以下配置
# 配置asgi
ASGI_APPLICATION = "application.asgi.application"

CHANNEL_LAYERS = {
    "default": {
        "BACKEND": "channels_redis.core.RedisChannelLayer",
        'CONFIG': {"hosts": ["redis://%s:%s/%s" % (REDIS_HOST, str(REDIS_PORT), str(REDIS_DB))], },
    }
}



4.notice_view 004文件

import json
import time

from django.core.cache import cache

from apps.web.dclient.view import push_msg
from apps.web.op_drf.response import SuccessResponse
from apps.web.op_drf.viewsets import GenericViewSet
from rest_framework.request import Request


class NoticeMessageView(GenericViewSet):
    """
    装修记录表
    """
    serializer_class = None
    authentication_classes = []
    permission_classes = []
    JWT_AUTH_COOKIE = ''

    def send_msg(self, request: Request, *args, **kwargs):
        """
        车牌消息推送
        """
        sn = self.request.query_params.get("sn")
        content = self.request.query_params.get("content")
        push_msg(sn, content)
        return SuccessResponse()

    def car_push(self, request: Request, *args, **kwargs):
        """
        demo
        {
            "AlarmInfoPlate":
                {
                    "channel": 0,
                    "deviceName": "IVS",
                    "ipaddr": "192.168.1.106",
                    "result":
                        {
                            "PlateResult":
                                {
                                    "bright": 0,
                                    "carBright": 0,
                                    "carColor": 0,
                                    "colorType": 1,
                                    "colorValue": 0,
                                    "confidence": 100,
                                    "direction": 0,
                                    "gioouts":
                                        [],
                                    "imagePath": "%2Fmmc%2FVzIPCCap%2F2023_02_10%2F1040291504_%CB%D5J2AX70.jpg",
                                    "isoffline": 0,
                                    "license": "苏J2AX70",
                                    "location":
                                        {
                                            "RECT":
                                                {
                                                    "bottom": 647,
                                                    "left": 1395,
                                                    "right": 1577,
                                                    "top": 587
                                                }
                                        },
                                    "plateid": 12331,
                                    "timeStamp":
                                        {
                                            "Timeval":
                                                {
                                                    "decday": 10,
                                                    "dechour": 10,
                                                    "decmin": 40,
                                                    "decmon": 2,
                                                    "decsec": 29,
                                                    "decyear": 2023,
                                                    "sec": 1675996829,
                                                    "usec": 157567
                                                }
                                        },
                                    "timeUsed": 112,
                                    "triggerType": 4,
                                    "type": 1
                                }
                        },
                    "serialno": "d604b906-3354aa7a",
                    "user_data": ""
                }
        }
        """
        AlarmInfoPlate = self.request.data.get("AlarmInfoPlate")
        try:
            serial_num = AlarmInfoPlate.get("serialno")
            license = AlarmInfoPlate.get("result").get("PlateResult").get("license")
            data = {
                "serialno": serial_num,
                "AlarmInfoPlate": AlarmInfoPlate,
            }
            # 处理业务逻辑
            """
            1.车牌信息
            2.设备sn号
            3.商户信息
            """
            merchant_info = {
                "merchant_id": int(time.time()),
                "license": license,
                "company_id": 35,
                "serial_num": serial_num
            }
            push_msg(serial_num, AlarmInfoPlate)
            cache.set(serial_num, json.dumps(merchant_info))
            return SuccessResponse(data=data)

        except Exception as e:
            print(e)
            return SuccessResponse()




5.apps 005文件
from django.apps import AppConfig


class WcompanyConfig(AppConfig):
    name = 'apps.web.dclient'



6.router 006文件

from django.urls import re_path
from rest_framework.routers import DefaultRouter

from apps.web.dclient.views.notice_view import NoticeMessageView

router = DefaultRouter()

urlpatterns = [
    # re_path('^test/send_msg/$', NoticeMessageView.as_view({'get': 'send_msg'})),  # 主动推送消息给客户端
    re_path('^car/car_push/$', NoticeMessageView.as_view({'post': 'car_push'})),  # 主动推送消息给客户端
]
urlpatterns += router.urls



7.urls 007文件

from django.urls import re_path
from rest_framework.routers import DefaultRouter

from apps.web.dclient.view import ChatConsumerSec


router = DefaultRouter()

urlpatterns = [
    # 车牌&商户信息获取
    re_path(r'ws/carwith', ChatConsumerSec.as_asgi()),
]
urlpatterns += router.urls




8.view 008文件

import time

from asgiref.sync import async_to_sync
from channels.db import database_sync_to_async
from channels.exceptions import StopConsumer
from channels.generic.websocket import AsyncWebsocketConsumer, AsyncJsonWebsocketConsumer, WebsocketConsumer
import json

from channels.layers import get_channel_layer
from django.core.cache import cache

class ChatConsumerSec(AsyncWebsocketConsumer):
    def __init__(self, *args, **kwargs):
        super().__init__(args, kwargs)
        self.msg = None
        self.room_group_name = None

    @database_sync_to_async
    def get_redis(self):
        serial_num = self.scope.get("sn")
        msg = cache.get(serial_num)
        if msg:
            self.msg = msg

    async def connect(self):
        self.room_group_name = self.scope['room_group_name']
        user = self.scope.get('user_id')
        if not user:
            print("User is not")
            await self.close()

        await self.channel_layer.group_add(
            self.room_group_name,
            self.channel_name
        )
        # 开启连接
        await self.accept()
        await self.get_redis()
        if self.msg:
            await self.send(text_data=self.msg)

    async def disconnect(self, close_code):
        # 断开连接时调用
        await self.channel_layer.group_discard(
            self.room_group_name,
            self.channel_name
        )
        raise StopConsumer()

    async def websocket_receive(self, message):
        """
        更加msg类型进行判断
        close 关闭连接
        merchant_info  获取商户信息
        """
        data = message.get('text', '{}')
        try:
            data = json.loads(data)
            msg_type = data.get("msg_type")
            if msg_type in ["close", "merchant_info"]:
                message = data.get('message')
                if msg_type == "merchant_info":
                    if self.msg:
                        await self.send(text_data=self.msg)
                elif msg_type == "close":
                    await self.close()
                if message:
                    await self.channel_layer.group_send(
                        self.room_group_name,
                        {
                            'type': 'notification_message',
                            'message': message
                        }
                    )

            else:
                await self.close()


        except Exception as e:
            print(e)

    async def notification_message(self, event):
        message = event['message']
        await self.send(text_data=json.dumps({
            'message': message,
        }))

    async def chat_message(self, event):
        # message = event['message']
        message = event.get("event")
        # Send message to WebSocket
        await self.send(text_data=json.dumps({
            'message': message,
        }))


def push_msg(sn, content):
    """
    :param username: 上面定义的组的名字
    :param event: 你要返回的消息内容,可以是str,dict
    :return:
    """
    sn = "chat-%s" % sn
    channel_layer = get_channel_layer()
    async_to_sync(channel_layer.group_send)(
        sn,
        {
            "type": "chat_message",  # 这个就是你上面 ChatConsumer 定义的 chat_message方法
            "event": content  # 是chat_message方法接受的参数
        }
    )



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值