簡體   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