django - React: How to send a multipart/form-data to a database
问题描述
I am currently setting up a file upload with React for the frontend and Django for the backend. More specifically, I want to pass a file + some data to my database via an API.
But while uploading the file I get the error: "The submitted data was not a file. Check the encoding type on the form."
models.py (Django)
class Story (models.Model):
title = models.CharField(max_length=100,blank=False)
content = models.TextField(blank=False)
author = models.ForeignKey(User, on_delete=models.CASCADE, null=True)
audio = models.FileField(default='SOME STRING', upload_to='audio_stories/',null=True, validators=[validate_file_extension_audio])
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse('story-detail', kwargs={'pk': self.pk})
serializers.py (Django)
class StorySerializer(serializers.ModelSerializer):
class Meta:
model = Story
fields = '__all__'
A MultiPartParser is used to pass file + data.
api.py (Django)
class StoryViewSet(viewsets.ModelViewSet) (Django):
serializer_class = StorySerializer
parser_classes = (MultipartJsonParser, parsers.JSONParser)
queryset = Story.objects.all()
permission_classes = [
permissions.IsAuthenticated
]
def perform_create(self, serializer):
serializer.save(author=self.request.user)
utils.py (Django)
class MultipartJsonParser(parsers.MultiPartParser):
def parse(self, stream, media_type=None, parser_context=None):
result = super().parse(
stream,
media_type=media_type,
parser_context=parser_context
)
data = {}
# find the data field and parse it
data = json.loads(result.data["data"])
qdict = QueryDict('', mutable=True)
qdict.update(data)
return parsers.DataAndFiles(qdict, result.files)
In actions story.js (React)
import axios from "axios";
import { tokenConfig } from './auth';
import { createMessage, returnErrors } from "./messages";
import {ADD_STORY} from "./types";
const apiBase = "http://localhost:8000/api";
export const addStory = story => (dispatch, getState) => {
axios
.post(apiBase +"/story/", story, tokenConfig(getState))
.then(res => {
dispatch(createMessage({ addStory: "Story Added" }));
dispatch({
type: ADD_STORY,
payload: res.data
});
})
.catch(err =>
dispatch(returnErrors(err.response.data, err.response.status))
);
};
In components create_story.js (React)
import React, { Component } from "react";
import { connect } from "react-redux";
import PropTypes from "prop-types";
import { addStory } from "../../actions/story";
export class CreateStory extends Component {
state = {
title: "",
content:""
};
static propTypes = {
addStory: PropTypes.func.isRequired
};
onChange = e => this.setState({ [e.target.name]: e.target.value });
onSubmit = e => {
e.preventDefault();
const { title,content, audio} = this.state;
const story = { title, content, audio};
this.props.addStory(story);
this.setState({
title: "",
content:"",
audio:""
});
};
render() {
const {title, content, audio} = this.state;
return (
<div className="card card-body mt-4 mb-4">
<h2>Add Story</h2>
<form onSubmit={this.onSubmit}>
<div className="form-group">
<label>Title</label>
<input
className="form-control"
type="text"
name="title"
onChange={this.onChange}
value={title}
/>
</div>
<div className="form-group">
<label>Content</label>
<input
className="form-control"
type="text"
name="content"
onChange={this.onChange}
value={content}
/>
</div>
<div className="form-group">
<label>Audio</label>
<input
className="form-control"
type="file"
name="audio"
onChange={this.onChange}
value={audio}
/>
</div>
<div className="form-group">
<button type="submit" className="btn btn-primary">
Submit
</button>
</div>
</form>
</div>
);
}
}
export default connect(
null,
{ addStory }
)(CreateStory);
I'm having trouble tracing the error in my code. I assume that the react form does not provide the correct data format, i.e. formdata. But i dont know how and wehre to change this. Without the file upload I was able to successfully pass data to my database.
Many thanks.
解决方案
Your onChange
function in create_story.js
is not gathering the file. You may need to reformat that function to something like:
onChange = (e) => {
if(e.target.name === 'audio') {
this.setState({
[e.target.name]: e.target.files[0]
}, () => console.log(this.state.audio))
} else {
this.setState({
[e.target.name]: e.target.value
}, () => console.log(this.state))
}
}
推荐阅读
- php - 只有一个提交按钮在 laravel 表单中的两个中工作
- graphql - react-apollo 解决缺失的字段
- laravel - 雄辩的一对一关系的奇怪行为
- ios - 实现水平和垂直滚动的 UIPageViewController 的最佳方式
- reactjs - 添加图层时,底图上的 Mapbox 单击侦听器失败
- javascript - 将所有数据导出到 Excel,包括来自分页的数据
- php - 注销时如何更改我的帐户菜单 Woocommerce 的链接
- python - 在 python 中为大数据集绘制时间序列的正确白天格式是什么?
- mysql - MySQL Window 函数计算百分比
- javascript - 如何从由斜杠分隔的 url 中获取 url 参数,例如 http://myweb.com/example/12345/222/4444 我想从上面的 url 中获取 12345、222、4444