Search code examples
pythonflaskflask-wtformswtformsfile-storage

Flask FileStorage save empty file


I am working with Flask, WTForms and Flask-WTF to save a file but the file is always store as an empty file. It doesn't show any error.

Form:

from flask_wtf import FlaskForm
from flask_wtf.file import FileField
from wtforms import StringField, SubmitField

class UserForm(FlaskForm):
    username = StringField('u', validators=[InputRequired()])
    email = StringField('e', validators=[InputRequired()])
    password = StringField('c', validators=[InputRequired()])
    signature = FileField('s')
    save = SubmitField('a')

Flask Route / Function:

@bp.route('/manage/user', methods=['GET', 'POST'])
@login_required
def manage_user():
    form = UserForm()
    action = 'create'

    try:        
        if form.validate_on_submit():
            if form.save.data:
                print('request.method', request.method)
                print('request.args', request.args)
                print('request.form', request.form)
                print('request.files', request.files)
                # archivo = request.files['signature']
                # archivo = request.files.items()[0]
                archivo = form.signature.data
                print(type(archivo))
                if archivo:
                    image_data = archivo.read()
                    basedir = os.path.abspath(os.path.dirname(__file__))
                    filename = secure_filename(form.username.data+'.png')
                    full_dir = os.path.join(basedir, '..\\static\\img', filename)
                    print(sys.getsizeof(archivo))
                    archivo.save(full_dir) 
                return redirect(url_for('main.manage'))
    except Exception as e:
        print(e)

    return render_template('manage_user.html', title=('Admon'), form=form, action=action)

HTML

<form action="" method="POST" role="form" class="form-horizontal" enctype="multipart/form-data">
    {{ form.csrf_token() }}
    <div class="form-group">
        <label class="control-label col-sm-3">Firma</label>
        <div class="col-sm-6">
            {% if action=='create' %}
            <!-- Other fields -->
            {{ form.signature(placeholder="Firma", type="file", class="form-control", accept="image/*", required="True") }}
            <img id="firmaimg" src="{{ url_for('static', filename='img/firma130x50_dummy.png') }}" alt="Firma" />
            {{ form.save(class="btn btn-success btn-md") }}
            {% endif %}
        </div>
    </div>
</form>

The print statements show this: Print results

The order of the prints is:

  1. Request method
  2. Request Arguments
  3. Request Form
  4. Request Files
  5. Type of archivo variable

Size of archivo is always 32, it doesn't matter what image I upload, is always 32, so from that point is already empty, haven't figure out why is coming empty. I'm following the examples.

https://flask-wtf.readthedocs.io/en/latest/form.html


Solution

  • Firstly, the size of your file is always 32 because sys.getsizeof() returns the amount of memory in bytes Python uses for that object, as explained in the docs.

    To print the actual file size you can use:

    os.path.getsize('path')
    

    Using it, you should see that the printed file size is effectively 0.

    Secondly, by removing:

    image_data = archivio.read()
    

    you should be able to successfully save the file in the desired location.

    I'm not sure what you are trying to accomplish with archivio.read().