将 Django 通道添加到 DRF
Addition Django Channels to DRF
我正在尝试将频道添加到我的项目以发送下载状态百分比。我有一个方法 download_file()
可以从多个端点将文件下载到服务器。
我必须向项目添加频道,但它是一个没有前端的 API。
asgi.py
import os
import django
from django.core.asgi import get_asgi_application
from src.apps import api
from channels.routing import ProtocolTypeRouter, URLRouter
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'src.settings')
django.setup()
application = ProtocolTypeRouter({
'http': get_asgi_application(),
'websocket': URLRouter(api.routing.websocket_urlpatterns),
})
settings.py
THIRD_PARTY_APPS = (
'...' ,
'channels',
)
# ...
# channels
ASGI_APPLICATION = 'src.asgi.application'
CHANNEL_LAYERS = {
"default": {
"BACKEND": "channels_rabbitmq.core.RabbitmqChannelLayer",
},
}
routing.py
from django.urls import path
from src.apps.api.consumers import DownloadStateConsumer
websocket_urlpatterns = [
path('download_state/', DownloadStateConsumer.as_asgi()),
]
consumers.py
from channels.generic.websocket import AsyncWebsocketConsumer
class DownloadStateConsumer(AsyncJsonWebsocketConsumer):
async def connect(self):
await self.accept()
async def receive(self, text_data=None, bytes_data=None, **kwargs):
await self.send_json({'message': text_data})
file_download.py
def download_file():
# ...
response = requests.get(link.link, stream=True)
total_length = response.headers.get('content-length')
size = 0
with response as r:
r.raise_for_status()
with open(filename, 'wb') as f:
state = -1
for chunk in r.iter_content(chunk_size=8192):
size += len(chunk)
f.write(chunk)
done = int(100 * size / int(total_length))
sys.stdout.write("\r%s%s" % (str(done), "%"))
if done != state:
async_to_sync(
get_channel_layer().group_send(
'download_state', {
'type': 'send.percent',
'message': done,
}
)
)
state = done
sys.stdout.flush()
# ...
我知道在客户端上脚本应该是这样的
const webSocket = new WebSocket(
'ws://'
+ window.location.host
+ '/download_state/'
);
webSocket.onmessage = function(e) {
const data = JSON.parse(e.data);
document.querySelector('#download-state').value = data.message;
};
webSocket.onclose = function(e) {
console.error('Chat socket closed unexpectedly');
};
问题是如何从download_file()
方法向客户端发送下载状态?当前方式不起作用 - 客户端不接收消息。谢谢!
最后我改为channels_redis
而不是channels_rabbitmq
:
CHANNEL_LAYERS = {
'default': {
'BACKEND': 'channels_redis.core.RedisChannelLayer',
'CONFIG': {
"hosts": [('127.0.0.1', 6379)],
},
},
}
我 运行 将 redis 图像放入指定端口上的 Docker,现在它可以工作了。
我正在尝试将频道添加到我的项目以发送下载状态百分比。我有一个方法 download_file()
可以从多个端点将文件下载到服务器。
我必须向项目添加频道,但它是一个没有前端的 API。
asgi.py
import os
import django
from django.core.asgi import get_asgi_application
from src.apps import api
from channels.routing import ProtocolTypeRouter, URLRouter
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'src.settings')
django.setup()
application = ProtocolTypeRouter({
'http': get_asgi_application(),
'websocket': URLRouter(api.routing.websocket_urlpatterns),
})
settings.py
THIRD_PARTY_APPS = (
'...' ,
'channels',
)
# ...
# channels
ASGI_APPLICATION = 'src.asgi.application'
CHANNEL_LAYERS = {
"default": {
"BACKEND": "channels_rabbitmq.core.RabbitmqChannelLayer",
},
}
routing.py
from django.urls import path
from src.apps.api.consumers import DownloadStateConsumer
websocket_urlpatterns = [
path('download_state/', DownloadStateConsumer.as_asgi()),
]
consumers.py
from channels.generic.websocket import AsyncWebsocketConsumer
class DownloadStateConsumer(AsyncJsonWebsocketConsumer):
async def connect(self):
await self.accept()
async def receive(self, text_data=None, bytes_data=None, **kwargs):
await self.send_json({'message': text_data})
file_download.py
def download_file():
# ...
response = requests.get(link.link, stream=True)
total_length = response.headers.get('content-length')
size = 0
with response as r:
r.raise_for_status()
with open(filename, 'wb') as f:
state = -1
for chunk in r.iter_content(chunk_size=8192):
size += len(chunk)
f.write(chunk)
done = int(100 * size / int(total_length))
sys.stdout.write("\r%s%s" % (str(done), "%"))
if done != state:
async_to_sync(
get_channel_layer().group_send(
'download_state', {
'type': 'send.percent',
'message': done,
}
)
)
state = done
sys.stdout.flush()
# ...
我知道在客户端上脚本应该是这样的
const webSocket = new WebSocket(
'ws://'
+ window.location.host
+ '/download_state/'
);
webSocket.onmessage = function(e) {
const data = JSON.parse(e.data);
document.querySelector('#download-state').value = data.message;
};
webSocket.onclose = function(e) {
console.error('Chat socket closed unexpectedly');
};
问题是如何从download_file()
方法向客户端发送下载状态?当前方式不起作用 - 客户端不接收消息。谢谢!
最后我改为channels_redis
而不是channels_rabbitmq
:
CHANNEL_LAYERS = {
'default': {
'BACKEND': 'channels_redis.core.RedisChannelLayer',
'CONFIG': {
"hosts": [('127.0.0.1', 6379)],
},
},
}
我 运行 将 redis 图像放入指定端口上的 Docker,现在它可以工作了。