Skip to content
Advertisement

upload multiple files with fetch

I am trying to receive more than one file per time using reactjs and flask api, but I get this error

data = file.read()
AttributeError: 'str' object has no attribute 'read'

fontend code using reactjs

this.state = {
  file : []
}

fileSelectHandler = (event) => {
  var totalfiles = event.target.files.length;
  for (var index=0; index < totalfiles; index++){
    this.state.file.push(event.target.files[index])
  }
}
    
async onFormSubmit (event) {
   event.preventDefault();
   const formData = new FormData();
   formData.append("file", this.state.file);    

   await fetch(apiUrl+'photo/create' , {
      method: 'POST',
      body: formData
   })
}

backend code using flask

@app.route('/photo/create', methods=['POST'])
def create_photo():
   files = request.form.getlist("file")
   print(files)

   for file in files:
      data = file.read()

flask receiving the files as [‘[object File],[object File]’] .

I tried to find ways to read an object file but nothing worked can anyone help..

Advertisement

Answer

I don’t use React but for me problem makes

formData.append("file", this.state.file);    

because this.state.file is list with one or many files and it needs for-loop to add every file as separated object in Form

const formData = new FormData();

var totalfiles = this.state.file.length;

for (var index=0; index < totalfiles; index++){
  formData.append("file", this.state.file[index]);    
}

And now it sends all files in request.files instead of one (useless) string '[object File],[object File]' in request.form


Minimal working code

from flask import Flask, request, render_template_string

app = Flask(__name__)

@app.route('/', methods=['GET', 'POST'])
def index():
    return render_template_string('''
<!DOCTYPE html>

<script>
this.state = {
  file: []
}

fileSelectHandler = (event) => {
  console.log("fileSelectHandler");
  var totalfiles = event.target.files.length;
  for (var index=0; index < totalfiles; index++){
    this.state.file.push(event.target.files[index]);
  }
}
    
async function onFormSubmit(event) {
  console.log("onFormSubmit");
  event.preventDefault();
   
  const formData = new FormData();

  var totalfiles = this.state.file.length;
  for (var index=0; index < totalfiles; index++){
    formData.append("file", this.state.file[index]);    
  }
  
  // doesn't need `http://.../` if sends to the same server
  await fetch('/photo/create',  
  {
    method: 'POST',
    body: formData,
  });
}
</script>

<input type="file" multiple onChange="fileSelectHandler(event);">
<button type="submit" onClick="onFormSubmit(event);">Submit</button>
''')

@app.route('/photo/create', methods=['GET', 'POST'])
def photo():
    print('args :', request.args)
    print('form :', request.form)
    print('json :', request.json)
    print('files:', request.files)
    for file in request.files.getlist('file'):
        print(file.filename)
        #print(file.read())
    return render_template_string(''' ''')

if __name__ == '__main__':
    #app.debug = True 
    app.run()  
User contributions licensed under: CC BY-SA
4 People found this is helpful
Advertisement