繁体   English   中英

如何将文件从 React 发送到 Django REST Framework?

[英]How to send files to Django REST Framework from React?

我需要将任意(例如xls )文件从基于 React 的前端发送到 Django REST Framework 后端。

谷歌搜索并尝试了几个小时的许多代码变体,但没有一个完全有效。

以下是代码的重要部分:

  1. 反应

1.1 表单输入字段

<input
    type="file"
    multiple={true}
    accept=".xls,.xlsx,.csv,.txt"
    onChange={this.handleFilesChosen}
/>

1.2 handleFilesChosen

    handleFilesChosen = event => {
        this.setState({
            files: event.target.files
        });
    }

1.3 上传点击处理程序( authHeader是代替 Authorization Bearer token 的函数)

    handleUploadClick = event => {
        let formData = new FormData();
        for (let file of this.state.files) {
            formData.append('files', file);
        }
        const csrf = this.getCookie('csrftoken');
        fetch(`${API_BASE_PATH}/load-input-data/`, {
            method: 'POST',
            headers: authHeader({contentType: 'multipart/form-data', csrf: csrf}),
            body: formData,
        })
        .then(result => result.json())
        .catch(error => error);
    }
  1. DRF 视图
class LoadInputDataView(APIView):
    parser_class = (MultiPartParser,)

    @method_decorator(login_required)
    def post(self, request, format=None):
        print(request.data)
        return Response(status=status.HTTP_201_CREATED)

我选择了简单的txt文件(使调试容易,双星将在稍后去)与hello world内容,上传,并得到<QueryDict: {}>在Django runserver控制台。

如果我查看 Chrome 网络选项卡,我会看到以下空请求负载而不是实际文件内容:

------WebKitFormBoundaryYw6ABRFkvxatzHqi
Content-Disposition: form-data; name="files"; filename="foo.txt"
Content-Type: text/plain


------WebKitFormBoundaryYw6ABRFkvxatzHqi--

试图删除contentType标头 - 出现 400 错误,消息JSON parse error (浏览器自动替换 JSON contentType 标头)。

我被困住了。 有人可以指导我吗?

找到解决方案。 我不应该手动设置Content-Type标头,它是使用boundary选项自动设置的。 现在 Django 的request.FILES也可以工作了,我可以使用如下代码处理从后端上传的文件:

class ParseInputDataView(APIView):
    parser_class = (MultiPartParser,)
    permission_classes = [permissions.IsAuthenticated]

    def post(self, request, controller_id, format=None):
        for file_entry in request.FILES.getlist('files'):
            uploaded_file_name = file_entry.name
            uploaded_file_content = file_entry.read()
            ...

我决定在 API 中保持一致性并在 JSON 中发送图像。

在反应中:

const [image, setImage] = useState(null);

  const handleImageChange = (e) => {
    e.preventDefault();
    const reader = new FileReader();
    reader.onload = () => {
      var blocks = reader.result.split(";");
      const realData = blocks[1].split(",")[1];
      setImage(realData);
    };
    reader.onerror = (error) => console.error(error);
    reader.readAsDataURL(e.target.files[0]);
  };

 const onSaveHandler = () => {
    fetch(`/url`, {
        method: "post",
        credentials: "include", // send cookie with auth
        headers: {
            "Content-Type": "application/json",
            "X-CSRFToken": document.getElementById("csrf-token").value,
        }
        body: JSON.stringify({imageData: image}),
     });
 }

return(
 <div>
      <input
        onChange={handleImageChange}
        id="logo"
        type="file"
        multiple="false"
        accept="image/*"
      />
      <button onClick={onSaveHandler}>
        SAVE
      </button>
 </div>);

在 Django (DRF) 中:

class CustomerViewSet(viewsets.ModelViewSet):
      # override create method
      def create(self, request, *args, **kwargs):
        image_path = "whatever.jpg"
        print('save image on disk: ' + image_path)
        with open(image_path, "wb") as fh:
            fh.write(base64.b64decode(request.data.get("imageData")))
        return super().create(request)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM