React + Django csv handle - reactjs

I'm working on a Data Mining app with React and Django, I kind of understand how to send the file to Django, but how do I read the file, apply an algorithm and return the process data to react for showing it? The objective of the app is to read a differente csv file each time, so, I don't need to create models, don't even need to store the data, just handle the information.
I've seen a lot of tutorials, but everyone make use of a database, is there a method to process the file without saving anything, just processing and return the process data for create graphs and stuff? how an I do that?
This is my attempt with a react component for sending the file to django, but now, whats next? how do I read it in django? and how do I send the process data back to react?
import { useState } from "react";
function DragDropFiles(){
const [selectedFile, setSelectedFile] = useState();
const [isFilePicked, setIsFilePicked] = useState(false);
const changeHandler = (event) => {
setSelectedFile(event.target.files[0]);
setIsFilePicked(true);
}
const handleSubmission = async () =>{
const formData = new FormData();
formData.append('File', selectedFile);
let newData = await fetch(
base_url,
{
method: 'POST',
headers: {
'Content-Type': 'multipart/form-data'
},
body: formData,
}
)
.then((response) => response.json())
.then((result) =>{
console.log('Success:', result);
})
.catch((error) =>{
console.log('Error:', error);
});
};
return(
<>
<div>
<input type="file" name="file" onChange={changeHandler} />
{isFilePicked ? (
<div>
<p>Filename: {selectedFile.name}</p>
<p>Filetype: {selectedFile.type}</p>
<p>Size in bytes: {selectedFile.size}</p>
</div>
) : (
<p>Select a file to show details</p>
)}
<div>
<button onClick={handleSubmission}>Submit</button>
</div>
</div>
</>
);
};
export default DragDropFiles;
I know that I have to import pandas, numpy and other libraries for handle data, but I mean, literally, how do I "receive" the csv file in the backend?
Thanks.

Related

Django API rejects file

I'm trying to send a csv file to my Django API and response with process data, but when I send it, I get the error:
django.utils.datastructures.MultiValueDictKeyError: 'file'
this is my react code:
import { useState } from 'react';
import './App.css';
function App() {
const [file, setFile] = useState(null);
const uploadFiles = e =>{
setFile(e);
}
const insertFile = async() => {
const f = new FormData();
f.append("file", file);
await fetch(
api,
{
method: 'POST',
headers: { 'content-type': 'multipart/form-data' },
body: f,
})
.then((response) => response.json())
.then((data)=>{
console.log(data);
})
.catch(error=>{
console.log(error);
});
}
return (
<>
<input type="file" name="file" onChange={(e)=>uploadFiles(e.target.files)}/>
<button onClick={()=>insertFile()}>Insertar</button>
</>
);
}
export default App;
And this is my view.py file that will process the information, for now, I just want to get the csv info in the frontend side, so the logic of how to process data doesn't matter right now.
#api_view(['POST'])
def eda(request):
file = request.FILES['file']
data = []
with open(file, encoding='utf-8') as csvf:
csvReader = csv.DictReader(csvf)
for rows in csvReader:
data.append(rows)
response = {
'csvData': data
}
return Response(response)
Seems like your files are not added in the FormData at all. It's because you are sending a list of files not a single file.
So instead of this
<input type="file" name="file" onChange={(e)=>uploadFiles(e.target.files)}/>
Use this
<input type="file" name="file" onChange={(e)=>uploadFiles(e.target.files[0])}/>
and on Django side use this:
file = request.FILES.get('file') # won't raise exception
if file is None:
# show some error response
Instead of request.FILES.get('file') try using request.data.get('file')

Upload file with React

I want to make a simple file upload form on the front end. Then, on the backend, I would pass the information about that file to an API.
Here is my front-end code where I call a specific function on the back end and pass the data:
import React from 'react';
import Axios from 'axios';
const Upload = () => {
// a local state to store the currently selected file.
const [selectedFile, setSelectedFile] = React.useState(null);
const handleSubmit = async (event) => {
event.preventDefault()
//Got all the Infos about my file
console.log(selectedFile)
const formData = new FormData();
formData.append("selectedFile", selectedFile);
//Empty result
console.log(formData)
Axios.get("http://localhost:3001/upload", {
//I will pass the data to a function in the backend
params: {
data: formData,
},
})
.then((Response) => {
console.log(Response)
})
.catch(function (error) {
console.log(error);
});
}
const handleFileSelect = (event) => {
setSelectedFile(event.target.files[0])
}
return (
<form onSubmit={handleSubmit}>
<input type="file" onChange={handleFileSelect}/>
<input type="submit" value="Upload File" />
</form>
)
};
export default Test
On the back-end side, a route call the method
router.get('/upload?', Upload);
Then finally the function in the backend to process
const ApiProcess = (req, res) => {
var axios = require('axios');
var data = req.query
console.log(req.query)
//All the API Stuff
}
But the problem is that I receive empty data in the Backend. What's wrong with my code?
Thanks
EDIT
On backend side I use multer and add 'app.use(multer().any())' on top of index file. That help cause now I cant access in backend to a simple formData. Now my function that receive the data log this '[Object: null prototype] {}'
Any idea ?
This is because your file is not getting forwarded from frontend
use FileReader instead
<input type="submit" value="Upload File" onChange={(e) =>
setFile(e.target.files)} />
const data = new FormData();
data.append(file[0])
and then you can access the file data on file[0] index and after storing the data you can forward it to the backend
there are some problems in your code.
first of all an upload request usually is a post type. and also you should send Content-Type header with your request. so:
Axios.post("http://localhost:3001/upload", formData {
headers: {
'Content-Type': 'Multipart/formData',
},
})
when you log formData it's always empty. you can use some methods like formData.keys() or formData.values() to see inside it.
Ok I got the solution. I missed a piece of middleware to process Multipart/formdata on Express Side :
const router = express.Router();
const multer = require("multer");
//Set the destination folder and Naming of the file that is upload
const storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, 'uploads/')
},
filename: function (req, file, cb) {
cb(null, file.originalname)
}
})
const upload = multer({ storage: storage })
Then I process the formData with the files
router.post('/upload', upload.array("file"),Upload);
Thanks a lot for your help

Better option for image upload (cloud) in NextJS

I'm currently developing my first real project for a client with NextJS and MongoDB and I'm having problems uploading images. I'm working with Cloudinary but it can't receive multiple files and I'm also having issues with state management because when the form is submitted my database doesn't receive the files whereas Cloudinary does.
The API works fine so I post here the code of the form (REACT).
export default function NewProduct() {
const initialState = {
title: "",
price: 0,
description: "",
content: "",
images: [],
category: "tortas",
};
const [product, setProduct] = useState(initialState);
const { title, price, description, content, category } = product;
const [files, setFile] = useState("");
//const handleChangeInput = (e) => {
// setProduct({ ...product, [e.target.name]: e.target.value });
//};
const handleUploadInput = async (e) => {
const uploadFiles = [...e.target.files];
setFile([...files, uploadFiles]);
};
const handleSubmit = async (e) => {
e.preventDefault();
const formData = new FormData();
for (let file of files) {
formData.append("file", file);
}
formData.append("upload_preset", "balbla");
const res = await fetch(
"https://api.cloudinary.com/v1_1/blabla/image/upload",
{
method: "POST",
body: formData,
}
);
const data = await res.json();
setProduct((p) => ({ ...p, images: data.secure_url}));
await createProduct();
setProduct(initialState);
};
const createProduct = async () => {
try {
const res = await fetch("http://localhost:3000/api/products", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(product),
});
const data = await res.json();
console.log(data);
} catch (err) {
console.log(err);
}
};
return (
<Layout>
<div className={styles.formDiv}>
<form className={styles.form} onSubmit={handleSubmit}>
<input
type="file"
name="file"
onChange={handleUploadInput}
multiple
accept="image/*"
/>
<button type="submit">Crear</button>
</form>
</div>
</Layout>
);
}
In case using Cloudinary isn't the best option with NextJS, what other cloud or stuff I could use?
I hope I made myself clear.
Thank you in advance.
The Cloudinary Upload API unfortunately doesn't support uploading multiple resources within a single request, so you would need to likely loop through all of your media items and upload them each individually.
As far as the production creation is concerned, I can't tell for sure, but you may be trying to create the product before your product state is updated.
Inside createProduct have you checked to see if all of the data you expect is available at the time it's being ran?
You could try listening to updates to the product state and create a product based off of that with a useEffect hook, for instnace:
useEffect(() => {
// Check if product is available or perform
// a check that you know isn't ready to create yet
if ( !product ) return;
(async function run() {
await createProduct(product);
setProduct(initialState);
})()
}, [product])

Sending an axios Post request with csv in its body

What i am trying to achieve is send a post request from my frontend to back end using axios.This post request has a csv file in its body.
Using postman : postman request
My code is this:
import React, { Component } from 'react';
import axios from 'axios'
class SessionsUpdate extends Component {
state = {
selectedFile: null
}
handleSubmit = async () => {
let formData = new FormData();
formData.append('file', this.state.selectedFile);
await axios.post(
'https://localhost:8765/...',
formData,
{ headers: { 'x-observatory-auth': localStorage.getItem("token"), 'Content-Type': 'multipart/form-data' } }
)
console.log("log") //this is not printed here
}
onFileChange = event => {
this.setState({ selectedFile: event.target.files[0] });
};
render() {
return (
<form onSubmit={this.handleSubmit}>
<div>
<h1>Choose a file to store</h1>
</div>
<div>
<fieldset>
<input type="file" accept=".csv" onChange={this.onFileChange} />
</fieldset>
</div>
<input type="submit" value="Submit" />
</form>
);
}
}
export default SessionsUpdate;
So the HTML part creates a simple GUI to select a csv file from local storage and what i want is to pass this csv file to my post request.After searching online the main way i found to do this is by using formdata but it does not work on my case and i have been stuck in this for quite a while.This requests works fine on postman though.
Any ideas about what i am missing?

How to post data into my React application?

I have an issue with my react, I'm working on a MERN template but I can't make my post to work, and I want to be able to add a new blog on my site. When I add a new blog, I seem to get it in my console.log. (the title and the description) but not on my app, I believe it's something with my fetch.
this is my app.js file
import React, {useEffect, useState} from 'react';
import {Router} from "#reach/router";
import Blogs from "./Blogs";
import Blog from "./Blog";
const API_URL = process.env.REACT_APP_API;
function App() {
const [blog, setBlogs] = useState([]);
const [postCount, setPostCount] = useState(0);
useEffect(() => {
async function getData() {
const url = `${API_URL}/blogs`;
const response = await fetch(url);
const data = await response.json();
setBlogs(data);
}
getData();
}, [postCount]);
function getBlog(id) {
const blogObject = blog.find(data => data._id === id);
return blogObject;
}
//callback så min addBlog ved hvor den skal hente data fra
async function addBlog(title, description, date) {
console.log("title", title);
console.log("Description" , description);
const newBlog = {
title: title,
description: description,
date: date
}
const url = `${API_URL}/blogs`;
const response = await fetch(url, {
method: 'POST',
headers: { 'Content-Type': 'application/json'
},
body: JSON.stringify(newBlog),
});
const data = await response.json();
//setBlogs([...blogs, newBlog]);
setPostCount(postCount + 1); //call my post count that fecths my data automatic
console.log("blog", data);
}
return (
<>
<h1>Blog App!</h1>
<Router>
<Blogs path="/" blogs={blog} addBlog={addBlog}>{blog.id}</Blogs>
<Blog path="/blogs/:id" getBlog={getBlog}></Blog>
</Router>
</>
);
}
export default App;
this is my addBlog.js
import React, { useState } from 'react';
function AddBlog(props) {
//state const for hver properties i din object(question)
const [title, setTitle] = useState("");
const [description, setDescription] = useState("");
const [date, setDate] = useState("");
return (
<><label>Title: </label>
<input type="text" placeholder="Write the title of your Blog" size="30" onChange={(event) => {
setTitle(event.target.value)
}
} /><br /><label>Description: </label>
<input type="text" placeholder="Write the description..." size="30" onChange={(event) => {
setDescription(event.target.value)
}} />
<br />
<button onClick={(event) => props.addBlog(title, description, date)}>Add Question</button>
</>
);
}
export default AddBlog;
I hope someone is able to help me out.
UPDATE here's my screendump of my console - when I press add blog it says POST 401 unAuthrorized.
SORRY IT WAS THE WRONG PROJECT I POSTED AN IMAGE BUT NOW IT'S THE RIGHT PROJECT
Screendump of my console
After looking at your logs, I think you need to send authorization headers alongside your fetch request in order for the back-end to respond.
You could add the authorization header like that - however, you need to find out/generate authorization token that your backend can accept. Also a little improvement, I would make the function a bit more dynamic by allowing it to accept an URL.
useEffect(() => {
async function getData(url) {
const response = await fetch(URL, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': <your auth token>
}
});
const data = await response.json();
setBlogs(data);
}
getData(`${API_URL}/blogs`);
}, [postCount]);

Resources