def upload_chunked_file(request, param_name, allow_memory=True): """ Загрузчик файлов, переданных от форм. Поддерживает передачу файла по частям. Возвращает обертку над файлом (возможно в памяти), удаляющимся после закрытия. Если allow_memory = False, то мелкие файлы, которые Django сохраняет в память, будут принудительно сохранены во временные файлы на диске. Пример: from libs.upload import upload_chunked_file, NotLastChunk, TemporaryFileNotFoundError ... try: uploaded_file = upload_chunked_file(request, 'image') except TemporaryFileNotFoundError as e: return JsonResponse({ 'message': str(e), }, status=400) except NotLastChunk: return HttpResponse() request.user.avatar.save(uploaded_file.name, uploaded_file, save=False) uploaded_file.close() try: request.user.avatar.field.clean(request.user.avatar, request.user) except ValidationError as e: request.user.avatar.delete(save=False) return JsonResponse({ 'message': ', '.join(e.messages), }, status=400) request.user.avatar.clean() request.user.avatar.save() """ file = request.FILES[param_name] chunk_num = int(request.POST.get('chunk', 0)) chunk_count = int(request.POST.get('chunks', 1)) if chunk_count == 1: # файл одним куском if not isinstance(file, InMemoryUploadedFile): return file elif allow_memory: return file else: # принудительное сохранение в файл tmp = TemporaryUploadedFile(file.name, file.content_type, file.size, file.charset, file.content_type_extra) for chunk in file.chunks(): tmp.write(chunk) tmp.seek(0) tmp.flush() return tmp else: # pluploader отправляет имя "blob" file.name = os.path.basename(request.POST.get('name', file.name)) # генерируем имя, которое можно восстановить при получении # следующих чанков name, ext = os.path.splitext(file.name) hashname = '%s.%s' % (request.META.get('REMOTE_ADDR'), name) hashname = hashlib.md5(hashname.encode()).hexdigest() tempfile_name = '%s.upload%s' % (hashname, ext) tempfile_path = os.path.join(tempfile.gettempdir(), tempfile_name) if chunk_num > 0: if not os.path.exists(tempfile_path): raise TemporaryFileNotFoundError(_('Temporary file lost')) tmp = open(tempfile_path, 'ab+') if chunk_num == 0: tmp.seek(0) tmp.truncate() for chunk in file.chunks(): tmp.write(chunk) if chunk_num < chunk_count - 1: tmp.close() raise NotLastChunk(chunk_num + 1, chunk_count) tmp.seek(0) tmp.flush() file_info = os.stat(tempfile_path) return TempUploadedFile(tmp, name=file.name, content_type=file.content_type, size=file_info.st_size, charset=file.charset, content_type_extra=file.content_type_extra)