Передача аудиофайлов в задачу 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, ключ базы данных, и т.д.) задаче. Затем задача может загрузить файл, сделать то, что ей нужно, и удалить оригинал (если это необходимо).

Вернуться на верх