Загрузить файлы на s3 с помощью задач сельдерея - PullRequest
0 голосов
/ 28 сентября 2018

Я пытаюсь загрузить видеофайл в s3, но после помещения в очередь задач с сельдереем.Во время загрузки видео пользователь может выполнять другие действия.

Мои views.py для вызова задач сельдерея

def upload_blob(request, iterator, interview_id, candidate_id, question_id):
    try:
        interview_obj = Interview.objects.get(id=interview_id)
    except ObjectDoesNotExist:
        interview_obj = None
    current_interview = interview_obj
    if request.method == 'POST':
        print("inside POST")
        # newdoc1 = Document(upload=request.FILES['uploaded_video'], name="videos/interview_"+interview_id+"_candidate_"+candidate_id+"_question_"+question_id)
        # newdoc1.save()
        save_document_model.delay(request.FILES['uploaded_video'],"videos/interview_"+interview_id+"_candidate_"+candidate_id+"_question_"+question_id)
        # newdoc2 = Document(upload=request.FILES['uploaded_audio'], name="audios/interview_"+interview_id+"_candidate_"+candidate_id+"_question_"+question_id)
        # newdoc2.save()
        save_document_model.delay(request.FILES['uploaded_audio'],"audios/interview_"+interview_id+"_candidate_"+candidate_id+"_question_"+question_id)
        iterator = str(int(iterator) + 1)

        return HttpResponseRedirect(reverse('candidate:show_question', kwargs={'iterator': iterator,'interview_id':current_interview.id,'question_id':question_id}))
    else:

        return render(request, 'candidate/record_answer.html')

Фактические задачи сельдерея.py

@task(name="save_document_model")
def save_document_model(uploaded_file, file_name):

    newdoc = Document(upload=uploaded_file, name=file_name)
    newdoc.save()

    logger.info("document saved successfully")
    return HttpResponse("document saved successfully")

Модель документа

def upload_function(instance, filename):
    getname = instance.name
    customlocation = os.path.join(settings.AWS_S3_CUSTOM_DOMAIN, settings.MEDIAFILES_LOCATION, getname)
    # Add other filename logic here
    return getname # Return the end filename where you want it saved.

class Document(models.Model):
    name = models.CharField(max_length=25)
    uploaded_at = models.DateTimeField(auto_now_add=True)
    upload = models.FileField(upload_to=upload_function)

Settings.py

AWS_ACCESS_KEY_ID = '**********************'
AWS_SECRET_ACCESS_KEY = '**************************'
AWS_STORAGE_BUCKET_NAME = '*********'
AWS_S3_CUSTOM_DOMAIN = '%s.s3.amazonaws.com' % AWS_STORAGE_BUCKET_NAME
AWS_S3_OBJECT_PARAMETERS = {
    'CacheControl': 'max-age=86400',
}
AWS_LOCATION = 'static'
AWS_DEFAULT_ACL = None

MEDIAFILES_LOCATION = 'uploads/'
DEFAULT_FILE_STORAGE = 'watsonproj.storage_backends.MediaStorage'

# CELERY STUFF
BROKER_URL = 'redis://localhost:6379'
CELERY_RESULT_BACKEND = 'redis://localhost:6379'
CELERY_ACCEPT_CONTENT = ['application/json']
CELERY_TASK_SERIALIZER = 'json'
CELERY_RESULT_SERIALIZER = 'json'
CELERY_TIMEZONE = 'Africa/Nairobi'
CELERY_IMPORTS=("candidate.tasks")

Прямая загрузка работает без сельдерея, но с сельдереем я получаю эту ошибку:

Объект типа 'InMemoryUploadedFile' не поддерживает сериализацию в формате JSON

1 Ответ

0 голосов
/ 29 сентября 2018

Celery дает возможность настроить способ сериализации полезных нагрузок задачи.

Сериализатор задач, настроенный в настройках вашего проекта, задает CELERY_TASK_SERIALIZER = json.

request.FILES['<input>'] - это экземпляр django.core.files.uploaded.files.InMemoryUploadedFile и не может быть закодирован напрямую с помощью сериализатора json ( Список поддерживаемых типов ).
Хотя существуют способы сериализации файлов в виде двоичных данных, если ваши пользователи загружают большие файлы, ваше приложение может использовать большие объемы памяти

Вы можете рассмотреть возможность использования django.core.files.uploadedfile.TemporaryFileUploadHandler в любом случае и переадресациивременный путь к файлу (request.FILES['<input>'] .temporary_file_path()) вместо request.FILES['<input>'] в полезной нагрузке задачи.

Чтобы применить это, настройте FILE_UPLOAD_MAX_MEMORY_SIZE = 0 в настройках проекта. Предупреждение: Это деактивирует MemoryFileUploadHandler для всего вашего проекта.

Впоследствии в определении задачи вы можете затем прочитать файл в память для сохранения.новый Document.

from django.core.files import File
from django.conf import DEFAULT_FILE_STORAGE as storage

@task(name="save_document_model")
def save_document_model(file_path, file_name):

    with open(file_path, 'r') as f:
        file = File(f)

        newdoc = Document(upload=file, name=file_name)
        newdoc.save()

        logger.info("document saved successfully")

        storage.delete(file_path) # cleanup temp file

    return HttpResponse("document saved successfully")
...