Как реализовать Django WebSockets?
Я пытаюсь создать простое приложение на Django, используя вебсокеты для отправки данных.
Согласно документации:
- Я добавил 'channels' в settings.py в INSTALLED APPS:
INSTALLED_APPS = [
"django.contrib.admin",
"django.contrib.auth",
"django.contrib.contenttypes",
"django.contrib.sessions",
"django.contrib.messages",
"django.contrib.staticfiles",
"channels",
"serial_mouse",
]
ASGI_APPLICATION = 'mouse_serial.asgi.application'
- Создали файл asgi.py, чтобы настроить ASGI:
import os
from django.core.asgi import get_asgi_application
from channels.routing import ProtocolTypeRouter, URLRouter
from channels.auth import AuthMiddlewareStack
from serial_mouse import routing
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'mouse_serial.settings')
application = ProtocolTypeRouter({
'http': get_asgi_application(),
'websocket': AuthMiddlewareStack(
URLRouter(
routing.websocket_urlpatterns
)
),
})
- Настройте файл routing.py для вебсокетов:
from django.urls import path
from . import consumers
websocket_urlpatterns = [
path('ws/serial/', consumers.SerialConsumer.as_asgi()),
]
- Реализовали потребителя WebSocket в только что созданном файле consumers.py:
import json
import asyncio
import os
import serial
import cv2
import time
from django.conf import settings
from channels.generic.websocket import AsyncWebsocketConsumer
from .models import Capture, MouseData
class SerialConsumer(AsyncWebsocketConsumer):
def __init__(self, *args, **kwargs):
super().__init__(args, kwargs)
self.serial_task = None
async def connect(self):
await self.accept()
self.serial_task = asyncio.create_task(self.read_serial())
async def disconnect(self, close_code):
self.serial_task.cancel()
async def receive(self, text_data):
data = json.loads(text_data)
if data['action'] == 'capture':
self.capture_image()
elif data['action'] == 'mouse_move':
self.save_mouse_data(data['x'], data['y'])
async def read_serial(self):
ser = serial.Serial('/dev/ttyUSB0', 9600)
while True:
line = ser.readline().decode('utf-8').strip()
await self.send(text_data=json.dumps({
'message': line,
}))
@staticmethod
def capture_image():
cam = cv2.VideoCapture(0)
ret, frame = cam.read()
if ret:
captures_dir = os.path.join(settings.BASE_DIR, 'static', 'captures')
if not os.path.exists(captures_dir):
os.makedirs(captures_dir)
filename = f'capture_{int(time.time())}.jpg'
filepath = os.path.join(captures_dir, filename)
cv2.imwrite(filepath, frame)
Capture.objects.create(filename=f'captures/{filename}')
@staticmethod
def save_mouse_data(x, y):
MouseData.objects.create(x=x, y=y)
- Реализованные функции views.py:
from django.shortcuts import render
from .models import Capture, MouseData
def index(request):
return render(request, 'serial_mouse/index.html')
def view_data(request):
captures = Capture.objects.all()
mouse_data = MouseData.objects.all()
return render(request, 'serial_mouse/view_data.html', {
'captures': captures,
'mouse_data': mouse_data
})
- Обновлен index.html для использования WebSockets:
<!DOCTYPE html>
<html>
<head>
<title>Mouse Serial App</title>
{% load static %}
<link rel="stylesheet" type="text/css" href="{% static 'styles.css' %}">
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
</head>
<body>
<nav>
<a href="/">Home</a>
<a href="/view_data/">View Data</a>
</nav>
<button id="capture-btn">Capture</button>
<script>
document.addEventListener('DOMContentLoaded', function() {
console.log("Index.html script loaded.");
const captureBtn = document.getElementById('capture-btn');
const socket = new WebSocket('ws://127.0.0.1:8000/ws/serial/');
socket.onopen = function() {
console.log("WebSocket connection established.");
};
socket.onerror = function(error) {
console.error("WebSocket error: ", error);
};
socket.onclose = function(event) {
if (event.wasClean) {
console.log(`WebSocket connection closed cleanly, code=${event.code}, reason=${event.reason}`);
} else {
console.error('WebSocket connection closed unexpectedly');
}
};
document.addEventListener('mousemove', function(event) {
const mouseData = {
action: 'mouse_move',
x: event.clientX,
y: event.clientY
};
console.log(`Sending mouse data: ${JSON.stringify(mouseData)}`);
socket.send(JSON.stringify(mouseData));
});
captureBtn.onclick = function() {
const captureAction = {'action': 'capture'};
console.log(`Sending capture action: ${JSON.stringify(captureAction)}`);
socket.send(JSON.stringify(captureAction));
};
socket.onmessage = function(event) {
const data = JSON.parse(event.data);
console.log(`Received message: ${data.message}`);
};
});
</script>
</body>
</html>
Приложение запускается, однако я получаю:
Firefox can’t establish a connection to the server at ws://127.0.0.1:8000/ws/serial/.
WebSocket error:
error { target: WebSocket, isTrusted: true, srcElement: WebSocket, eventPhase: 0, bubbles: false, cancelable: false, returnValue: true, defaultPrevented: false, composed: false, timeStamp: 261, … }
WebSocket connection closed unexpectedly
Та же проблема и в Chrome. Приложение отлично работает с Ajax. Однако оно не может установить соединение с веб-сокетами. Может быть, я что-то упускаю?
Я пробовал использовать разные браузеры. Я ожидаю, что приложение будет работать.