I am gettting the error: [ErrorDetail(string='The submitted data was not a file. Check the encoding type on the form.', code='invalid')], for submitting an image/file.
I added the encryption type for the form 'multipart/form-data' same thing in Axios call too, but I still get the same error.
I have a model like this:
class MyModel(models.Model):
img = models.ImageField(upload_to='media',blank=False)
In views.py:
class MyModelView(viewset.ModelViewSet):
serializer_class = serializer.MyModelSerializer
def post(self,request):
data = serializer.MyModelSerializer(data=request.data)
print(data.is_valid()) # this is false, means there is an error
print(data.errors) #This one will display the error shown in the title of this question
if data.is_valid():
img = data.data['img']
return Response('Success')
return Response('Fail')
In serializer.py:
class MyModelSerializer(serializers.ModelSerializer):
class Meta:
model = MyModel
fields = '__all__'
In frontend side (React):
function ImgComp(){
let [img,setImg] = useState({'image':''}
let {image} = img
function handleChange(e){
setImg(
{
...img,[e.target.name]:e.target.value
}
)
}
function submitForm(e){
e.preventDefault()
axios.post('127.0.0.1:8000/mymodelurl/',img,{withCredentials:true,headers:{'Content-Type':'multipart/form-data'}})
return(
<div>
<form method='post' encType='multipart/form-data' onSubmit = {(e)=>submitForm(e)}>
<input type='file' value={image} name='img' onChange={(e)=>handleChange(e)}/>
</form>
</div>
}
}
If I debug the img I get something like:
C:\\fakepath\\img.png
I have a an external form which submits a post request to my nuxt app. I am struggling currently to find out how I can access these POST request parameters in my nuxt page?
I found so far the "asyncData" method, but when I try to access the submitted parameter through the "params" object it is always "undefined". What do I wrong here?
"asyncData" nuxt reference
example code in my nuxt page, assuming "email" is the request parameter submitted from outside
export default {
asyncData({ params }) {
console.log('asyncData called...' + params.email);
return {email: params.email};
},
external html form
<body>
<form action="https://..." target="_blank" method="post">
<input name="email" class="input" type="text" placeholder="Email" maxlength="255"></input>
<input name="submit" class="btn" type="submit" value="Ok"></input>
</form>
</bod>
I found a way, as described in "asyncData" nuxt reference you can pass the request and response object to the "asyncData({req,res})" call.
Here an example - assuming 'email' is one of the post parameter. querystring is a module of node.js and allows you to parse the request body into an array.
Small Remark - this seems only to work for nuxt page level components but not for lower level components
<script>
export default {
asyncData({ req, res }) {
if (process.server) {
const qs = require('querystring');
var body = '';
var temp = '';
while(temp = req.read()) {
body += temp;
}
var post = qs.parse(body);
return {data: post};
}
},
data() {
return {
data: '',
}
},
mounted() {
console.log(this.data['email']);
},
</script>
Nuxt.js cannot handle such things by itself.
https://nuxtjs.org/api/configuration-servermiddleware
You should implement your own middleware for such cases.
And asyncData has nothing to do with handling inbound POST data.
I created small test application using Angular 4 and Nodejs. I want to insert a text field value to the database either Mongo or mysql.
Following files I created server.js for running nodejs, Created server>router folder with another file api.js and Angular 4 user component created.
What i did code shown below
user.component.html
<form (submit)="addHobby(hobbies,hobby.value)">
<input type="text" #hobby>
<input type="submit" value="Submit">
</form>
user.component.ts
addHobby(arrHob,hobby) {
if(arrHob.indexOf(hobby) == -1) {
this.hobbies.unshift(hobby);
this.dataService.postHobby(hobby).subscribe((posts) => {
console.log(posts);
})
}
return false;
}
Services folder contain data.service.ts
postHobby(hobby) {
return this.http.post('/api/insertHobby',hobby).map(res => res.json().data);
}
server router folder contain api.js
router.post('/insertHobby', (req, res) => {
console.log("Welcome to post method");
console.log(req.body.data);
})
When form submitting i'm getting output as only welcome to post method
req.body.data i'm getting as *'Undefined'* How to resolve this issue. Any way thanks to everyone..
since you are not passing the variable as object , you need to pass it in object format as below :
postHobby(hobby) {
return this.http.post('/api/insertHobby',{hobby: hobby}).map(res => res.json().data);
}
Im trying to upload a file with React and see its contents, but what it gives me is C:\fakepath\. I know why it gives fakepath, but what is the correct way to upload and read the contents of a file in react?
<input type="file"
name="myFile"
onChange={this.handleChange} />
handleChange: function(e) {
switch (e.target.name) {
case 'myFile':
const data = new FormData();
data.append('file', e.target.value);
console.log(data);
default:
console.error('Error in handleChange()'); break;
}
},
To get the file info you want to use event.target.files which is an array of selected files. Each one of these can be easily uploaded via a FormData object. See below snippet for example:
class FileInput extends React.Component {
constructor(props) {
super(props)
this.uploadFile = this.uploadFile.bind(this);
}
uploadFile(event) {
let file = event.target.files[0];
console.log(file);
if (file) {
let data = new FormData();
data.append('file', file);
// axios.post('/files', data)...
}
}
render() {
return <span>
<input type="file"
name="myFile"
onChange={this.uploadFile} />
</span>
}
}
ReactDOM.render(<FileInput />, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.6.1/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.6.1/react-dom.min.js"></script>
<div id="root"></div>
You may want to look into FileReader which can help if you want to handle the file on the client side, for example to display an image.
https://developer.mozilla.org/en-US/docs/Web/API/FileReader
You can use React Dropzone Uploader, which gives you file previews (including image thumbnails) out of the box, and also handles uploads for you.
In your onChangeStatus prop you can react to the file's meta data and the file itself, which means you can do any kind of client-side processing you want before or after uploading the file.
import 'react-dropzone-uploader/dist/styles.css'
import Dropzone from 'react-dropzone-uploader'
const Uploader = () => {
return (
<Dropzone
getUploadParams={() => ({ url: 'https://httpbin.org/post' })} // specify upload params and url for your files
onChangeStatus={({ meta, file }, status) => { console.log(status, meta, file) }}
onSubmit={(files) => { console.log(files.map(f => f.meta)) }}
accept="image/*,audio/*,video/*"
/>
)
}
Uploads have progress indicators, and they can be cancelled or restarted. The UI is fully customizable.
Full disclosure: I wrote this library.
Try to use Multer and gridfs-storage on the back end and store the fileID along with your mongoose schema.
// Create a storage object with a given configuration
const storage = require('multer-gridfs-storage')({
url: 'MONGOP DB ATLAS URL'
});
// Set multer storage engine to the newly created object
const upload = multer({ storage }).single('file');
router.post('/', upload, (req, res) => {
const newreminder = new Reminders({
category: req.body.category,
name:req.body.name,
type: req.body.type,
exdate: req.body.exdate,
location:req.body.location,
notes:req.body.notes,
fileID: req.file.id
});
newreminder.save(function(err){
if(err){
console.log(err);
return;
}
res.json({ "success": "true"});
});
});
Then on the front end treat it normally (with Axios) and upload the entire file and grab a hold of all the info in the normal react way:
onSubmit = (e) => {
e.preventDefault;
const formData = new FormData();
formData.append({ [e.target.name]: e.target.value })
formData.append('file', e.target.files[0]);
axios.post({
method:'POST',
url:'EXPRESS JS POST REQUEST PATH',
data: formData,
config:{ headers: {'Content-Type':'multipart/form-data, boundary=${form._boundary}'}}
})
.then(res => console.log(res))
.catch(err => console.log('Error', err))
}
Have you use dropzone ?
see this react-dropzone
easy implement, upload and return url if this important.
onDrop: acceptedFiles => {
const req = request.post('/upload');
acceptedFiles.forEach(file => {
req.attach(file.name, file);
});
req.end(callback);
}
You can use FileReader onload methods to read the file data and then can send it to the server.
You can find this useful to handle files using File Reader in React ReactJS File Reader
To add to the other answers here, especially for anyone new to React, it is useful to understand that react handles forms a little differently than people may be used to.
At a high level, react recommends using 'Controlled components" :
In most cases, we recommend using controlled components to implement forms. In a controlled component, form data is handled by a React component. The alternative is uncontrolled components, where form data is handled by the DOM itself.
This essentially means that the user input, e.g. a text field, is also a state of the component and as the user updates it the state is updated and the value of the state if displayed in the form. This means the state and the form data are always in synch.
For an input type of file this will not work because the file input value is read-only. Therefore, a controlled component cannot be used and an 'uncontrolled component' is used instead.
In React, an is always an uncontrolled component because its value can only be set by a user, and not programmatically.
The recommended way to input a file type (at the time of writing) is below, from the react documentation here https://reactjs.org/docs/uncontrolled-components.html#the-file-input-tag:
class FileInput extends React.Component {
constructor(props) {
super(props);
this.handleSubmit = this.handleSubmit.bind(this);
this.fileInput = React.createRef();
}
handleSubmit(event) {
event.preventDefault();
alert(
`Selected file - ${this.fileInput.current.files[0].name}`
);
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<label>
Upload file:
<input type="file" ref={this.fileInput} />
</label>
<br />
<button type="submit">Submit</button>
</form>
);
}
}
ReactDOM.render(
<FileInput />,
document.getElementById('root')
);
The documentation includes a codepen example which can be built on.
I'm building a front end tool that allows users to upload a CSV file to a certain end point. I use the HTML5 input="file"
Here is my JSX, I use the React Dropzone library:
<Dropzone
multiple={false}
onDrop={this.onDrop}
>
<div>
<input type="file" />
</div>
</Dropzone>
The onDrop function:
onDrop(acceptedFile) {
this.setState({ file: acceptedFile });
}
I grab that file and put it on my state. My submit function looks like this:
submitFile() {
const formData = new FormData();
formData.append('uploadCsv', this.state.file);
fetch('/api/person/uploadfile', {
body: formData,
method: 'POST'
});
}
It then goes through a few files for routing..
router.use('/person', require('./routers/personRoutes').default);
router.post('/uploadfile', fileUpload);
Then I run my fileUpload function:
export const fileUpload = post({
route: req => {
return `${BASE_URL}/v1/fileupload/persons`;
}
});
Here I have no idea what to do. Usually I just have to return a URL and everything works. req.body is just an empty object - {}. The error message I get back says:
Current request is not a multipart request
BUT. Something as simple as this does work:
<html>
<form action="http://localhost:9275/v1/fileupload/persons"
enctype="multipart/form-data" method="post">
<p>
Please specify a file, or a set of files:<br>
<input type="file" name="file" size="40">
</p>
<div>
<input type="submit" value="Send">
</div>
</form>
</html>
I've looked all over stack overflow and none of solutions have helped thus far :( the coworker who wrote the node stuff left so I'm alone on this