使用 django 频道和 websockets

Posted

技术标签:

【中文标题】使用 django 频道和 websockets【英文标题】:Working with django channels and websockets 【发布时间】:2016-08-07 06:45:55 【问题描述】:

我有一个表单可以在 127.0.0.1:8000/dashboard/ 输入线坐标,并有一个“确定”按钮来提交坐标。通过调用视图LineDisplay(),将坐标发布在127.0.0.1:8000/api/line/。这里我想将 Line 坐标推回 127.0.01:8000/dashboard/

到目前为止,我已经完成了以下工作:

urls.py:

from django.conf.urls import url,include
from django.contrib import admin
from . import views

urlpatterns = [
    url(r'^api/line/$',views.LineDisplay.as_view()),
]

view.py:

class LineDisplay(APIView):
"""
Display the most recent line
"""

    def get(self, request, format=None):
        lines = Line.objects.all()
        serializer = LineSerializer(lines, many=True)
        return Response(serializer.data)

    def post(self, request, format=None):
        lines = Line.objects.all()
        for line in lines:
            line.delete();
        serializer = LineSerializer(data=request.data)
        if serializer.is_valid():
            serializer.save()
        info = ""
        info += "Line Coordinates are: "
        lines = Line.objects.all()
        for line in lines:
            info += "x1:" + str(line.x1)
            info += " y1:" + str(line.y1)
            info += " x2:" + str(line.x2)
            info += " y2:" + str(line.y2)
        print info
        Channel('repeat-me').send('info': info, 'status': True)
        return Response(serializer.data, status=status.HTTP_201_CREATED)
    return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

consumers.py

import json

# In consumers.py
from channels import Group

# Connected to websocket.connect
def ws_add(message):
    Group("chat").add(message.reply_channel)

# Connected to websocket.receive
def ws_message(message):
     print "Receive Message now"
     Group("chat").send(
        "text": json.dumps('status': False)
    )
# Connected to websocket.disconnect
def ws_disconnect(message):
    Group("chat").discard(message.reply_channel)


def repeat_me(message):
    Group("chat").send(
    "text": json.dumps('status': message.content['status'], 'info':      
     message.content['info'])
     )

同样,我添加了以下代码:routing.py

from channels.routing import route
from .consumers import ws_add, ws_message, ws_disconnect, repeat_me

channel_routing = [
    route("websocket.connect", ws_add),
    route("websocket.receive", ws_message),
    route("websocket.disconnect", ws_disconnect),
    route("repeat-me", repeat_me),
]

settings.py 中添加了以下几行:

CHANNEL_LAYERS = 
    "default": 
        "BACKEND": "asgiref.inmemory.ChannelLayer",
        "ROUTING": "TrainingInduct.routing.channel_routing",
    ,

目前,我不知道如何处理群组“聊天”。我什至不需要组。为了在发布新行后立即将行坐标显示在 127.0.0.1:8000/dashboard/ 处,还需要做什么?

注意:线坐标正在正确发布到 /api/line/ 我想我可能必须编写一个服务器代码才能从通道中获取数据并将其推回,我我对吗?谢谢。

【问题讨论】:

【参考方案1】:

您需要该群组收集所有应该接收您的信息的频道。每个连接的设备都有一个通道。

设备的通道标识符在message.reply_channel 中。群组只是收集所有message.reply_channels 的一种方式。

因此,假设任何打开您的/dashboard/ 页面的用户都会收到任何发布的新“信息”项目。首先,您需要记住新客户的频道。这就是你的ws_add 的用途

def ws_add(message):
    Group("all-my-clients").add(message.reply_channel)

现在刚刚连接的客户端是all-my-clients 组的一部分,您通过all-my-clients 发送的任何消息也会自动发送到该客户端。

你当然想自己清理,这就是ws_disconnect 的用途。一旦他们执行 WebSocket.close() 或关闭浏览器等,删除客户端。

def ws_disconnect(message):
    Group("all-my-clients").discard(message.reply_channel)

最后,还有你的ws_message()。它接收任何传入的消息。

def ws_message(message):
    # Nothing to do here, because you only push, never receive.
    pass

就是这样。现在,您可以从 Django 中的任何位置向上面定义的组发送消息。只需确保以正确的格式发送响应即可。 Group().send() 接受一个 dict 和一个键 text ,该键具有一个字符串值(见下文)。原因是您还可以发送其他数据类型,例如 blob。但“文本”最适合此目的。

def post(self, request, format=None):
    lines = Line.objects.all()
    ...
    print info
    response_data = 'info': info, 'status': True
    Group("all-my-clients").send(
        'text': json.dumps(response_data)
    )
    return Response(serializer.data, status=status.HTTP_201_CREATED)

应该就是这样了。

【讨论】:

以上是关于使用 django 频道和 websockets的主要内容,如果未能解决你的问题,请参考以下文章

使用 django 频道和 websockets

使用 python 3.8 在 windows 10 上安装 django 频道和扭曲的问题

Django 频道“组订阅中 N 个频道中的 ERROR Y 超出容量”

使用 Daphne 和 Nginx 部署 django 频道的问题

使用没有视图的 Django 频道

使用 django 频道时如何使用频道而不是组?