Добавление каналов Django в DRF

#python #django-rest-framework #websocket #django-channels #channels

Вопрос:

Я пытаюсь добавить канал в свой проект, чтобы отправить процент загрузки. У меня есть метод 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() метода? Текущий способ не работает — клиент не получает сообщений. Спасибо!

Ответ №1:

В конце концов, я перешел на channels_redis instead channels_rabbitmq :

 CHANNEL_LAYERS = {  'default': {  'BACKEND': 'channels_redis.core.RedisChannelLayer',  'CONFIG': {  "hosts": [('127.0.0.1', 6379)],  },  }, }  

Я запустил изображение redis в Docker на указанном порту, и теперь оно работает.