DForsyth
DForsyth

Reputation: 508

Flask-WTF File Upload with wtforms not passing validation

I'm trying to upload a file to a Flask Form and having trouble passing the verification. I've been following the docs and have tried both this current method and the CombinedMultiDict() submission into the forms with no luck. I've printed out the error which is..

print(form.validate_on_submit())
False
print(form.errors)
{'upload': ['This field is required.']}

Imports..

import os
from flask import Flask, render_template, request, flash, redirect, url_for, session, logging
from flask_mysqldb import MySQL
from wtforms import Form, SelectField, StringField, TextAreaField, PasswordField, BooleanField,validators
from flask_wtf import FlaskForm
from flask_wtf.file import FileField, FileRequired, FileAllowed
from werkzeug.utils import secure_filename

Here is my form..

class UploadFileForm(FlaskForm):
    file_name = StringField('File Title', [
        validators.Length(min=4, max=35, message="File Title must be between 4 & 35 characters."),
        validators.Regexp(username_reg, message="File Title can contain only letters, numbers or underscores.")
    ])
    file_desc = TextAreaField('Body', [
        validators.Length(max=500),
        validators.Regexp(group_reg, message="The description can only contain letters, numbers, underscores, dashes, exclaimation/question marks, or periods."),
        validators.Optional()
    ])
    upload = FileField('File', validators=[FileRequired()])

My view...

@app.route('/upload_file', methods=['GET', 'POST'])
def upload_file():
    form = UploadFileForm():
    if form.validate_on_submit(): 
        print('========================')
        # file_name = secure_filename(form.file.data)
        file_name = form.file_name.data
        file_desc = form.file_desc.data
        file_path = os.path.join(app.config['UPLOAD_FOLDER'], secure_filename(form.upload.data.filename))
        form.upload.data.save(file_path)

        # Get user and group
        user = User.query.filter_by(username=session.get('username')).first()
        group = Group.query.filter_by(groupname=session.get('groupname')).first()

        # Add to DB
        new_file = File(file_name=file_name, file_desc=file_desc, file_path=file_path, uploader=user.username, user=user, group=group)
        db.session.add(new_file)
        db.session.commit()

        flash('File Uploaded!')
        return redirect(url_for('dashboard'))
    return render_template('upload_file.html', form=form)

HTML Page...

{% extends 'layout.html'%}

{% block body %}
    <h1>Upload File</h1>
    {% from "includes/_formhelpers.html" import render_field %}
    <form method="POST" action="" enctype="multipart/form-data">
        {{ form.csrf_token }}
        <div class="form-group">
        {{render_field(form.file_name, class_="form-control")}}
        </div>
        <div class="form-group">
        {{render_field(form.file_desc, class_="form-control")}}
        </div>
        <div class="form-group">
        {{render_field(form.upload, class_="form-control")}}
        </div>
        <input type="submit" class="btn btn-primary" value="Submit">
    </form>
{% endblock %}

When I submit the file it just ignores the submitted file which causes the validation to fail. Am I validating it wrong, or messed up the form?

Thanks in advance!

--UPDATE--
Still struggling with the blank file issue. I've played with the form and html a bit, but I'm still not getting any input when I submit the form.

New Form (Just changed the upload field a tad and added a form-made submit)...

class UploadFileForm(FlaskForm):
    file_name = StringField('File Title', [
        validators.Length(min=4, max=35, message="File Title must be between 4 & 35 characters."),
        validators.Regexp(username_reg, message="File Title can contain only letters, numbers or underscores.")
    ])
    file_desc = TextAreaField('Body', [
        validators.Length(max=500),
        validators.Regexp(group_reg, message="The description can only contain letters, numbers, underscores, dashes, exclaimation/question marks, or periods."),
        validators.Optional()
    ])
    upload = FileField('File', validators=[FileRequired(), FileAllowed(['txt', 'pdf', 'png', 'jpg', 'jpeg', 'gif', 'ppt'], 'Invalid File Type. Must be .txt, .pdf, .png, .jpeg')])
    submit = SubmitField('Post')

New HTML (Just changed the submit button, added fieldset tag out of desperation, and changed the form.upload input)...

<h1>Upload File</h1>
    {% from "includes/_formhelpers.html" import render_field %}
    <form method="POST" action="" enctype=“multipart/form-data”>
        {{ form.csrf_token }}
        <fieldset class="form-group">
            <div class="form-group">
                {{render_field(form.file_name, class_="form-control")}}
                </div>
                <div class="form-group">
                {{render_field(form.file_desc, class_="form-control")}}
                </div>
                <div class="form-group">
                {{ form.upload(class="form-control-file") }}
                </div>
        </fieldset>
        <div class="form-group">
            {{ form.submit(class="btn btn-primary") }}
        </div>
    </form>

The view is unchanged. I seems the problem is centralized in the html form since the form posts without a problem. Am I handling the file import form wrong?

Upvotes: 3

Views: 4283

Answers (2)

szkkteam
szkkteam

Reputation: 51

As suggested here, the solution is to change:
form = UploadFileForm(request.form)
to:
form = UploadFileForm()

Upvotes: 0

DForsyth
DForsyth

Reputation: 508

Finally fixed it. Changed the form to...

{% block body %}
    <h1>Upload File</h1>
    {% from "includes/_formhelpers.html" import render_field %}
    <form method="POST" action="" enctype="multipart/form-data">
        {{ form.hidden_tag() }}
        <fieldset class="form-group">
            <div class="form-group">
                {{render_field(form.file_name, class_="form-control")}}
            </div>
            <div class="form-group">
                {{render_field(form.file_desc, class_="form-control")}}
            </div>
            <div class="form-group">
                {{ form.upload.label() }}
                {{ form.upload(class="form-control-file") }}
            </div>
        </fieldset>
        <div class="form-group">
            {{ form.submit(class="btn btn-outline-info") }}
        </div>
    </form>
{% endblock %}

Also adjusted some other import stuff.

Upvotes: 1

Related Questions