How to upload multiple files with flask-wtf?
Asked Answered
S

2

12

I am trying to upload multiple files with flask-wtf. I can upload a single file with no problems and I've been able to change the html tag to accept multiple files but as of yet I haven't been able to get more than the first file.

The attached code will give me the first file but I can't figure out how to get any more files from it. I suspect that "render_kw={'multiple': True}" just changes the HTML tag so I might be barking up the wrong tree with this approach. I have also stumbled across "MultipleFileField" from wtforms but I can't seem to get that to return any files, again likely since it doesn't play nice with the flask_wtf I'm trying to use. Is there a good way to do this?

@app.route('/', methods=['GET', 'POST'])
def upload():
    form = Upload_Form(CombinedMultiDict((request.files, request.form)))
    if form.validate_on_submit():
        files = form.data_file.data
        files_filenames = secure_filename(files.filename)
        data.save(os.path.join(app.config['UPLOAD_FOLDER'], data_filename))
        print(files_filenames)
        return render_template('input_form.html', form=form)
    return render_template('input_form.html', form=form)

class Upload_Form(FlaskForm):
    data_file = FileField(render_kw={'multiple': True}, validators=[FileRequired(), FileAllowed(['txt'], 'text files only')])

<!--input_form.html--->
<form method=post enctype="multipart/form-data">
<table>
    {{ form.hidden_tag() }}
    {% for field in form %}
    <tr>
        <td>{% if field.widget.input_type != 'hidden' %} {{ field.label }} {% endif %}</td><td>{{ field }}</td>
    </tr>
    {% endfor %}
</table>
<p><input type=submit value=Compute></form></p>

This returns the first file but I need it to return all files selected. A list would be most useful but any data structure that I can unpack would work. Thanks.

Sincere answered 21/12, 2018 at 19:53 Comment(0)
S
24

Instead of using the FileField, use the MultipleFileField. It supports multiple files.

For example:

from wtforms import MultipleFileField

class NewFileForm(FlaskForm):
    files = MultipleFileField('File(s) Upload')

Then to access the files:

@app.route('/', methods=['GET', 'POST'])
def upload():
    form = NewFileForm()
    if form.validate_on_submit():
        files_filenames = []
        for file in form.files.data:
            file_filename = secure_filename(file.filename)
            data.save(os.path.join(app.config['UPLOAD_FOLDER'], data_filename))
            files_filenames.append(file_filename)
        print(files_filenames)
        return render_template('input_form.html', form=form)
    return render_template('input_form.html', form=form)
Schist answered 2/1, 2019 at 18:35 Comment(6)
Awesome thanks! I think the part of my problem was actually the validators breaking the upload. I removed that and processed form.files.data in a loop as suggested and it's working now.Sincere
= form.data_file.data doesn't seem like valid syntax. What am I missing?Apetalous
Not sure how that got messed up - I fixed the answer. That line shouldn't be there at all!Schist
This was a useful answer for me: https://mcmap.net/q/910863/-multiplefilefield-wtformsOleomargarine
where is data and data_filename defined?Tellurion
Doesn't work for me. When I try this files is a string and I get the error message, that the string files does not have the attribute filename.Summersault
J
3
from wtforms import MultipleFileField
from werkzeug.utils import secure_filename

class Upload_Form(FlaskForm):
   files = MultipleFileField(render_kw={'multiple': True})

And the route

@app.route('/', methods=['GET', 'POST'])
def upload():
   form = Upload_Form()
   if form.validate_on_submit():
      for file in form.files.data:
         file_name = secure_filename(file.filename)
         file.save(file_name)
Jemima answered 20/5, 2020 at 15:40 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.