Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Flask-WTF FileField does not set data attribute to an instance of Werkzeug FileStorage

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.

like image 691
Ashoat Avatar asked Oct 05 '13 22:10

Ashoat


1 Answers

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.

like image 145
Ashoat Avatar answered Sep 29 '22 22:09

Ashoat