React:如何将多部分/表单数据发送到数据库

时间:2020-03-31 16:52:35

标签: django reactjs react-redux

我目前正在使用React的前端和Django的后端设置文件上传。更具体地说,我想通过API将文件+一些数据传递到数据库。

但是在上传文件时出现错误:“提交的数据不是文件。请检查表单上的编码类型。”

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__'

MultiPartParser用于传递文件和数据。

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)

在操作story.js(实际)

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))
    );
};

在组件中create_story.js(反应)

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);

我在查找代码中的错误时遇到麻烦。我假设react表单没有提供正确的数据格式,即formdata。但是我不知道该如何改变我们。没有文件上传,我就能够成功地将数据传递到数据库中。

非常感谢。

1 个答案:

答案 0 :(得分:0)

您在onChange中的create_story.js函数未收集文件。您可能需要将该函数重新格式化为以下格式:

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))
        }
    }