Flask-WTF's documentation states that:
Flask-WTF provides you a FileField to handle file uploading, it will automatically draw data from flask.request.files if the form is posted. The data attribute of FileField will be an instance of Werkzeug FileStorage.
However, when I use FileField
, the data
attribute after posting is not a FileStorage
object. Instead, it is either None
(if I define my form with enctype="multipart/form-data"
as suggested in the documentation) or the filename as a string (if I don't define an enctype
).
Here is the relevant Jinja2 template:
{% from "_form.html" import render_field %}
{% block body %}
<section class="page-width-container" id="offset-content">
<div id="utility-box">
<h1 class="utility-header">Settings</h1>
{{ message }}
<form action="/settings" method="post" enctype="multipart/form-data">
{{ render_field(form.photo) }}
<input type="submit" class="form-action" value="Save" />
</form>
</div>
</section>
{% endblock %}
The _form.html macro:
{% macro render_field(field) %}
<div class="field">
{{ field.label }}
<span class="form-input">{{ field()|safe }}</span>
<div class="clear"></div>
{% if field.errors %}
<ul class="errors">
{% for error in field.errors %}
<li>{{ error }}</li>
{% endfor %}
</ul>
{% endif %}
</div>
{% endmacro %}
And here is the Python:
from flask import Blueprint, render_template, request
from flask.ext.wtf import Form
from flask.ext.wtf.file import FileField, FileRequired
settings_bp = Blueprint('settings', __name__)
class SettingsForm(Form):
photo = FileField('Photo', validators=[
FileRequired('no file!'),
])
@settings_bp.route('/settings', methods=['GET', 'POST'])
def login():
form = SettingsForm(request.form)
form.validate_on_submit()
print(type(form.photo.data))
return render_template('settings.html', form=form, message=form.photo.data)
With the enctype
attribute on the form
element, the printed type is NoneType
; without the enctype
attribute, the printed type is unicode
. Neither is the FileStorage
object advertised by the documentation.
I looked into the source code (form.py
) and figured out the issue: the code to replace the default data attribute with the FileStorage
object is not activated if the form is initialized with a specific formdata
. The formdata
must be left unspecified in order for the file functionality to work. Replacing this line:
form = SettingsForm(request.form)
With this line:
form = SettingsForm()
Resolved the issue.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With