Передача аудиофайлов в задачу Celery
У меня есть приложение для загрузки музыки, и я считаю, что было бы разумно передавать файлы в задачу celery для обработки загрузки. Однако при попытке передать файлы, как я покажу в своем коде ниже, я получаю сообщение о том, что они не являются JSON-сериализуемыми. Каким должен быть правильный способ обработки этой операции?
Все, что ниже uploaded_songs в .views.py - это мой текущий код, который успешно загружает звуковые дорожки. Однако он еще не использует celery.
.task.py
from django.contrib.auth import get_user_model
from Beyond_April_Base_Backend.celery import app
from django.contrib.auth.models import User
@app.task
def upload_songs(songs, user_id):
try:
user = User.objects.get(pk=user_id)
print('user and songs')
print(user)
print(songs)
except User.DoesNotExist:
logging.warning("Tried to find non-exisiting user '%s'" % user_id)
.views.py
class ConcertUploadView(APIView):
permission_classes = [permissions.IsAuthenticated]
def post(self, request):
track_files = request.FILES.getlist('files')
current_user = self.request.user
upload_songs.delay(track_files, current_user.pk)
try:
selected_band = Band.objects.get(name=request.data['band'])
except ObjectDoesNotExist:
print('band not received from form')
selected_band = Band.objects.get(name='Band')
venue_name = request.data['venue']
concert_date_str = request.data['concertDate']
concert_date_split = concert_date_str.split('(')[0]
concert_date = datetime.strptime(concert_date_split, '%a %b %d %Y %H:%M:%S %Z%z ')
concert_city = request.data['city']
concert_state = request.data['state']
concert_country = request.data['country']
new_concert = Concert(
venue=venue_name,
date=concert_date,
city=concert_city,
state=concert_state,
country=concert_country,
band=selected_band,
user=current_user,
)
new_concert.save()
i = 0
for song in track_files:
audio_metadata = music_tag.load_file(track_files[i].temporary_file_path())
temp_path = song.temporary_file_path
song_title = str(audio_metadata['title'])
audio_file_instance = Song(
title=song_title,
concert=new_concert,
user=current_user,
concert_order = i + 1,
audio_file = track_files[i],
)
audio_file_instance.save()
i += 1
return Response(status=status.HTTP_201_CREATED)
Когда вы создаете задачу celery, она сериализует аргументы, чтобы можно было сохранить сообщение в бэкенде очереди (RabbitMQ, Redis и т.д.). Сериализатором по умолчанию является JSON, а двоичный файл не является JSON-сериализуемым. Смотрите документы по сериализации вcelery для получения дополнительной информации.
Вы можете закодировать двоичный файл в текст с помощью base64, но не стоит: это увеличит размер данных, и вы будете передавать потенциально очень большие сообщения. При большом количестве больших сообщений у вас может закончиться память/пространство в бэкенде, и это затруднит проверку или регистрацию сообщений.
Вместо этого, вы должны хранить бинарный файл где-то, и передать ссылку (имя файла, URL S3, ключ базы данных, и т.д.) задаче. Затем задача может загрузить файл, сделать то, что ей нужно, и удалить оригинал (если это необходимо).