【发布时间】:2021-06-15 00:51:51
【问题描述】:
问题总结
我正在使用 Django 和 web-sockets 将数据发送到前端(React 组件)。当我运行应用程序并从控制台发送数据时,一切正常。当我使用前端的按钮触发运行相同功能的 Django 视图时,它不起作用并生成令人困惑的错误消息。
我希望能够单击开始将数据发送到 websocket 的前端按钮。
我是 Django、websockets 和 React 的新手,因此请您耐心等待。
概述
- Django 后端和 React 前端使用 Django 通道(网络套接字)连接。
- 用户点击前端的按钮,这在 Django REST API 端点上执行
fetch()。 - [不工作]上述端点的视图开始通过网络套接字发送数据。
- 使用此值更新前端。
简短的错误说明
错误 Traceback 很长,所以在文末附上。开头是:
内部服务器错误:/api/run-create
结尾是:
ConnectionResetError: [WinError 10054] 现有连接被远程主机强行关闭
我的尝试
在 Django 视图外部发送数据
- 下面的函数将数据发送到 web-socket。
- 当我在控制台中运行它时完美运行 - 前端更新符合预期。
- 注意:当从 Django 视图内部运行时,相同的函数会导致附加错误。
import json
import time
import numpy as np
import websocket
def gen_fake_path(num_cities):
path = list(np.random.choice(num_cities, num_cities, replace=False))
path = [int(num) for num in path]
return json.dumps({"path": path})
def fake_run(num_cities, limit=1000):
ws = websocket.WebSocket()
ws.connect("ws://localhost:8000/ws/canvas_data")
while limit:
path_json = gen_fake_path(num_cities)
print(f"Sending {path_json} (limit: {limit})")
ws.send(path_json)
time.sleep(3)
limit -= 1
print("Sending complete!")
ws.close()
return
其他细节
相关文件和配置
consumer.py
class AsyncCanvasConsumer(AsyncWebsocketConsumer):
async def connect(self):
self.group_name = "dashboard"
await self.channel_layer.group_add(self.group_name, self.channel_name)
await self.accept()
async def disconnect(self, close_code):
await self.channel_layer.group_discard(self.group_name, self.channel_name)
async def receive(self, text_data=None, bytes_data=None):
print(f"Received: {text_data}")
data = json.loads(text_data)
to_send = {"type": "prep", "path": data["path"]}
await self.channel_layer.group_send(self.group_name, to_send)
async def prep(self, event):
send_json = json.dumps({"path": event["path"]})
await self.send(text_data=send_json)
相关视图.py
@api_view(["POST", "GET"])
def run_create(request):
serializer = RunSerializer(data=request.data)
if not serializer.is_valid():
return Response({"Bad Request": "Invalid data..."}, status=status.HTTP_400_BAD_REQUEST)
# TODO: Do run here.
serializer.save()
fake_run(num_cities, limit=1000)
return Response(serializer.data, status=status.HTTP_200_OK)
相关设置.py
WSGI_APPLICATION = 'evolving_salesman.wsgi.application'
ASGI_APPLICATION = 'evolving_salesman.asgi.application'
CHANNEL_LAYERS = {
"default": {
"BACKEND": "channels.layers.InMemoryChannelLayer"
}
}
相关路由.py
websocket_url_pattern = [
path("ws/canvas_data", AsyncCanvasConsumer.as_asgi()),
]
完全错误
编辑:解决方案
Kunal Solanke 的建议解决了这个问题。我没有使用fake_run(),而是使用了以下内容:
layer = get_channel_layer()
for i in range(10):
path = list(np.random.choice(4, 4, replace=False))
path = [int(num) for num in path]
async_to_sync(layer.group_send)("dashboard", {"type": "prep", "path": path})
time.sleep(3)
【问题讨论】:
标签: django websocket django-channels