Python server store csv file sent from React client - javascript

As the title says, I have a client page that allows the user to upload files, they will always be .csv files.
export const sendFiles = async (files) => {
let form = new FormData();
form.append("arrFile", files);
await axios
.post(local + "/read-files", form, {
headers: { "Content-Type": "multipart/form-data" },
})
.then((res) => {
return res.data;
})
.catch((err) => {
return err;
});
};
This is the code I have for sending the files, using FormData. The files is an array of File objects. It can have just one or many. The files array on console looks like this
Array [ File ]
0: File { name: "filename.csv", lastModified: 1624560497968, size: 1244, … }
​​ lastModified: 1624560497968
name: "filename.csv"
size: 1244
type: "application/vnd.ms-excel"
webkitRelativePath: ""
<prototype>: FilePrototype { name: Getter, lastModified: Getter, webkitRelativePath: Getter, … }
length: 1
<prototype>: Array []
I'm sending this to my Python Flask server
#app.route("/read-files", methods=['POST'])
def read_files():
if request.method == 'POST':
form = dict(request.form)
return
I found that the FormData is stored in request.form, but when I print this data on Python it shows as such.
{'arrFile': '[object File],[object File],[object File],[object File],[object File],[object File],[object File]'}
The files seem to be in a string separated by commas. What I'd like to do is be able to store these files and their content, and be able to read them afterwards. Is this possible?

if {your_file_name} in request.files:
file = request.files['your_file_name']

Related

FormData not sending File object through Post request

I am making an axios.post() request in my Vue component to send some formData holding a media File to upload through a PHP script. I know the file object is being appended correctly as I log the data before the request here:
// this.postMedia is a Vue array holding any post media objects to be uploaded
this.postMedia.forEach((mediaObj, index) => {
formData.append('media[' + index + ']', mediaObj.media);
formData.append('mediaType[' + index + ']', mediaObj.mediaType);
});
// Logging formData
for (let p of formData.values()) {
console.log(p);
}
This logs the information of the file object and the corresponding media type as expected.
// This is the media data
File {
lastModified: 1627299857401
lastModifiedDate: Mon Jul 26 2021 07:44:17 GMT-0400 (Eastern Daylight Time) {}
name: "test-image.jpg"
size: 12295
type: "image/jpeg"
webkitRelativePath: ""
}
// This is the mediaType data
1
I am then passing this data through an axios request and logging the response data as follows:
// Vue.js file
axios.post('/api/createPostV2', formData, config)
.then(success => {
console.log(success.data);
})
.catch(function(err) {
console.log(err.response);
});
// PHP file being requested (/api/createPostV2)
public static function createPostV2(Request $request)
{
// Just return request to check data
return $request->all();
}
Here is what gets logged:
media: Array(1)
0: {}
length: 1
[[Prototype]]: Array(0)
mediaType: ['1']
So it is passing the media array, but the actual file is not being passed as you can see by the empty object at index 0. As you can see the mediaType is passed correctly, keep in mind both 'media' and 'mediaType' are arrays to support uploading multiple files. Am I missing something here? Why is the file data being lost when I am passing it through formData?

Upload file Vue 3 and Django REST

I dont get if i work with request correctly, after upload all files is 1 KB and i cant open them. How to create correct file? If i save file as .doc i can see:
------WebKitFormBoundaryt3UjlK5SVq8hgppA
Content-Disposition: form-data; name="file"
[object FileList]
------WebKitFormBoundaryt3UjlK5SVq8hgppA--
So my functions to submit in js file:
async submitFiles() {
let formData = new FormData();
formData.append('file', this.file);
console.log(this.file)
axios.put(`/api/v1/myapp/upload/${this.file[0].name}`,
formData,
{
headers: {
'Content-Disposition': 'attachment',
'X-CSRFToken': await this.getCsrfToken(),
},
}
).then(function () {
console.log('SUCCESS!!');
})
.catch(function () {
console.log('FAILURE!!');
});
},
To handle change of file in form
fileChanged(file) {
this.file = file.target.files
},
And finally my view.py
class FileUploadView(APIView):
parser_classes = [FileUploadParser]
def put(self, request, filename, format=None):
file_obj = request.data['file']
handle_uploaded_file(file_obj)
return Response({'received data': request.data})
Where
def handle_uploaded_file(f):
with open('path/to/my/folder/' + str(f.name), 'wb+') as destination:
for chunk in f.chunks():
destination.write(chunk)
[object FileList]
Oh, you serialized the whole FileList.
Change to: formData.append('file', this.file[0]);
If this won't work you may need to read the file's content.
Edit: it should be enough, according to MDN:
The field's value. This can be a USVString or Blob (including subclasses such as File). If none of these are specified the value is converted to a string.

Posting image to laravel with Axios only passing [object file] as string

I have a react app that is the frontend for a laravel application. I am using a simple image uploader that returns the uploaded file to a post route. In the controller for the post route the request is coming in as a string and not the actual object. see my code.
onUpload = (picture) => {
this.setState({
pictures: this.state.pictures.concat(picture),
});
var curr = this
const formData = new FormData();
formData.append('file',picture)
console.log(picture[0])
axios
.post('/upload-subitem-image', formData, fileHeaders)
.then(function (response) {
const data = response.data
console.log(data)
})
.catch(error => {
console.log(error);
})
}
When i console the picture object I get
File {name: "test.png", lastModified: 1553443959805, lastModifiedDate: Sun Mar 24 2019 12:12:39 GMT-0400 (Eastern Daylight Time), webkitRelativePath: "", size: 11695, …}
But after passing it to laravel to try and get the file it returns a string when i try to do this.
$data = $request->File();
and looks like
{file:{"[object file]"}
Headers look like this:
const fileHeaders = {
'X-CSRF-TOKEN' : document.querySelector('meta[name="csrf-token"]').getAttribute('content'),
'content-type': 'multipart/form-data',
'Accept': 'application/json',
}
Judging from the surrounding code, it looks like you're append-ing an array picture.
The API for FormData expects a File or Blob for file uploads so for an array it just turns it into a string. Since your array only has one item, it becomes [object file].
Try doing picture[0] in the append (And make sure to do proper bounds checks etc.)
Ref: https://developer.mozilla.org/en-US/docs/Web/API/FormData/Using_FormData_Objects#Sending_files_using_a_FormData_object
Ended up adding some stuff to controller in php.
$data = $request->all();
$file = $data['file'];

Upload JSON file using Angular 6

I'm trying to load a JSON file from the user using this method:
<input
style="display: none"
type="file" (change)="onFileChanged($event)"
#fileInput>
<button (click)="fileInput.click()">Select File</button>
<button (click)="onUpload()">Upload!</button>
and this is the code in the component ts file:
export class MyFileUploadComponent {
selectedFile: File
onFileChanged(event) {
this.selectedFile = event.target.files[0];
console.log(this.selectedFile);
console.log('content: ' + JSON.stringify(this.selectedFile));
}
onUpload() {
// upload code goes here
}
}
the line console.log(this.selectedFile); does provide me with the file meta data which is:
lastModified: 1551625969247
lastModifiedDate: Sun Mar 03 2019 17:12:49 GMT+0200 (Israel Standard Time) {}
name: "manuscripts.json"
size: 6008
type: "application/json"
webkitRelativePath: ""
__proto__: File
But when I'm trying to print it's content using JSON.stringify I get: {} (empty file).
What's the cause?
Thanks.
But when I'm trying to print it's content using JSON.stringify I get: {} (empty file).
This is not a content of JSON file. It's a File object. To read content of JSON you need to use FileReader
onFileChanged(event) {
this.selectedFile = event.target.files[0];
const fileReader = new FileReader();
fileReader.readAsText(this.selectedFile, "UTF-8");
fileReader.onload = () => {
console.log(JSON.parse(fileReader.result));
}
fileReader.onerror = (error) => {
console.log(error);
}
}
JSON.Stringify does not work for File objects in TS/JS. You should extract data from File and then stringify it.
For examlple, extract file content as a string or array of strings using https://developer.mozilla.org/en-US/docs/Web/API/FileReader

Client side compression with HTML5 and Javascript

Am working on a web application and we allow users to upload files to our server. Am trying to do client side compression before uploading files to the server. What would be the better way to achieve this using HTML5 and JavaScript.
Thanks.
The common mechanism to do what you want is using FileReader and a JavaScript client-side compression library (i.e. compressjs).
In 2022 it's almost too simple, if the browser supports CompressionStream, FormData and Response.
In the example below I use FormData to collect all the fields from the form.
Then I use the readable stream from the file, and pipe it though the compression stream. Then I use Response to read everything from the compressed stream and return it in a blob.
async function compress(file, encoding = 'gzip') {
try {
return {
data: await new Response(file.stream().pipeThrough(new CompressionStream(encoding)), {
headers: {
'Content-Type': file.type
},
}).blob(),
encoding,
};
} catch (error) {
// If error, return the file uncompressed
console.error(error.message);
return {
data: file,
encoding: null
};
}
}
theForm.addEventListener(
'submit',
(event) => event.preventDefault()
)
theForm.addEventListener(
'input',
async function(event) {
// collect all fields
const fd = new FormData(theForm);
// Get 'file handle' from imput elemen
const file = fd.get('theFile');
if (!file) return
const encoding = fd.get('theEncoding');
const compressed = await compress(file, encoding);
theMessage.value = [
'Compressed with', compressed.encoding,
'Source file was', file.size, 'bytes',
'and the compressed file', compressed.data.size,
'saving', ((1 - compressed.data.size / file.size) * 100)
.toFixed(0),
'%.'
].join(' ')
}
)
form>* {
display: block;
width: 100%;
}
<form id="theForm">
<select name="theEncoding">
<option>gzip</option>
<option>deflate</option>
<option>deflate-raw</option>
</select>
<input type="file" name="theFile" id="theFile">
</form>
<output id="theMessage"></output>

Categories