1

I'm trying to upload a file via Fetch, to a Django REST endpoint.

Component with Fetch Code:

function myComponent(props) {
  const classes = useStyles();
  const [{token}] = useContext();

  function handleImageUpload(files) {
    let formData = new FormData()
    formData.append('file', files[0])

    fetch(receiveSpreadsheetEndpoint, {
      method: 'POST',
      body: formData,
      headers: {
        'Content-Type': 'application/json',
        Authorization: `Bearer ${token}`,
      },
    })
      .then(response => response.json())
      .then(data => {
        console.log(data)
      })
      .catch(error => {
        console.error(error)
      })
  }

  function Dropzone(props) {
    const [files, setFiles] = useState([]);

    function handleChange(event) {
      setFiles(event[0]);
    }

    return (
      <>
        <DropzoneArea
          onChange={event => handleChange(event)}
        />

        <Button
          variant="contained"
          color="primary"
          onClick={event => handleImageUpload([files])}
        >
          Primary
        </Button>
      </>
    )
  }

  return (
    <Container className={classes.root} height="100%">
      <Dropzone
        acceptedFiles={['.csv', 'text/*', 'text/csv']}
        showPreviews={true}
        showFileNamesInPreview={true}
      />

    </Container>
  );
}

Django REST endpoint:

class ReceiveFileData(APIView):
    permission_classes = (IsAuthenticated,)
    parser_classes = (JSONParser, FormParser, MultiPartParser)

    def post(self, request):
        my_file = request.stream.read 

        data = {} <== a breakpoint is set here
        return Response(data, status=status.HTTP_200_OK)

After my_file = request.stream.read, my_file contains b''.

What am I leaving out?

UPDATE

Here's the request object when it arrives at the REST endpoint on the server:

enter image description here

1 Answer 1

3

This is now working. Here is working code in case it may be helpful to others.

REACT

import React, {useEffect, useRef, useState, Component} from 'react';
import 'typeface-roboto';
import {makeStyles} from '@material-ui/styles';
import {useContext} from "../../context";
import Container from "@material-ui/core/Container";
import {DropzoneArea} from 'material-ui-dropzone'
import Button from "@material-ui/core/Button";

//ENDPOINTS
const receiveSpreadsheetEndpoint = '/spreadsheet_generator/api/receive-spreadsheet/';

function UploadSpreadsheet(props) {
  const classes = useStyles();
  const [{token}] = useContext();

  function handleImageUpload(event, theFile) {
    event.stopPropagation();
    event.preventDefault();

    let formData = new FormData()
    formData.append('file', theFile)
    fetch(receiveSpreadsheetEndpoint, {
      method: 'POST',
      body: formData,
      headers: {
        Authorization: `Bearer ${token}`,
      },
    })
      .then(response => response.json())
      .then(data => {
        console.log(data)
      })
      .catch(error => {
        console.error(error)
      })
  }

  function Dropzone(props) {
    const [file, setFile] = useState(null);

    function handleChange(event) {
      setFile(event[0]);
    }

    return (
      <>
        <DropzoneArea
          onChange={event => handleChange(event)}
          filesLimit={1}
        />

        <Button
          variant="contained"
          color="primary"
          onClick={event => handleImageUpload(event, file)}
        >
          Primary
        </Button>

      </>
    )
  }

  return (
    <Container className={classes.root} height="100%">
      <Dropzone
        acceptedFiles={['.csv', 'text/*', 'text/csv']}
        showPreviews={true}
        showFileNamesInPreview={true}
      />
    </Container>
  );
}

//https://material-ui.com/components/buttons/
const useStyles = makeStyles(theme => ({
    root: {
      '& > *': {
        margin: theme.spacing(1),
      },
    },
  }))
;

export default UploadSpreadsheet;

DJANGO REST ENDPOINT

from rest_framework import status
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from rest_framework.views import APIView
from rest_framework.parsers import FormParser, MultiPartParser, JSONParser, FileUploadParser
import logging

from server_modules.spreadsheet.models import SourceSpreadsheet

logger = logging.getLogger(__name__)

logging.basicConfig(
    level=logging.DEBUG,
    format='%(name)s %(levelname)s %(message)s',
)

def create_spreadsheet_record(file):
    # insert record to SourceSpreadsheet
    SourceSpreadsheet.objects.create(file=file)

class ReceiveData(APIView):
    permission_classes = (IsAuthenticated,)
    parser_classes = (FileUploadParser,)

    def post(self, request):
        success = True
        message = 'OK'
        file = request.stream.FILES['file']

        # save to db
        try:
            create__spreadsheet_record(file)
        except Exception as e:
            print("Error calling ReceiveData: " + str(e))
            message = str(e)
            success = False

        data = {'message': message }
        if (success):
            return Response(data, status=status.HTTP_200_OK)
        else:
            return Response(data, status=status.HTTP_400_BAD_REQUEST)

DJANGO MODEL

class SourceSpreadsheet(models.Model):
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)
    file = models.FileField(upload_to='source_spreadsheets/%Y/%m')

BASE.PY Add:

MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.