Tri
Tri

Reputation: 3039

Flask-WTF 'FileField' object has no attribute 'has_file'

I combine Flask-WTF and Flask-upload to handle file upload on my App.

My package versions are:

Flask-Uploads==0.2.1
Flask-WTF==0.11
WTForms==2.1

Here is the snippet of my code:

forms.py

from flask_wtf import Form
from flask_wtf.file import FileAllowed, FileRequired
from wtforms.fields import (StringField, SubmitField, FileField)
from wtforms.validators import InputRequired, Length
from app import photos

class AddCourseForm(Form):
    name = StringField('Course name', validators=[InputRequired(), Length(1, 100)])
    image = FileField('image', validators=[FileRequired(), FileAllowed(photos, 'Images only!')])
    submit = SubmitField('Add course')

And here is the snippet of the upload code:

@operator.route('/add-course', methods=['GET', 'POST'])
def add_course():
    form = AddCourseForm()
    if form.validate_on_submit():
        course_name = form.name.data
        filename = photos.save(request.files['image'], name="courses/" + course_name + "_course.")
        course = Course(name=course_name, image=filename)
        db.session.add(course)
        db.session.commit()
        flash('Successfully added {} '.format(course.course_name()) + 'course', 'success')
        return redirect(url_for('operator.courses'))
    return render_template('main/operator/add_course.html', form=form)

But, when I submitted that, I got this following error:

AttributeError: 'FileField' object has no attribute 'has_file'

Then I tried to following this documentation, without Flask-Upload by passing the extensions directly:

image = FileField('image', validators=[FileRequired(), FileAllowed(['jpg', 'png'], 'Images only!')])

But I still got the same error.

So, what's wrong with my code..? Please, any help would be appreciated :)

Upvotes: 1

Views: 2572

Answers (1)

SuperShoot
SuperShoot

Reputation: 10861

You import FileField from the wtforms library:

from wtforms.fields import (StringField, SubmitField, FileField)

... but the FileField.has_file() method is specific to Flask-WTF.

You need to add FileField to the other imports from flask_wtf.file.

You can access the API documentation of Flask-WTF.file.FileField here.

The current implementation (found here) is:

class FileField(_FileField):
    """Werkzeug-aware subclass of :class:`wtforms.fields.FileField`."""

    def process_formdata(self, valuelist):
        valuelist = (x for x in valuelist if isinstance(x, FileStorage) and x)
        data = next(valuelist, None)

        if data is not None:
            self.data = data
        else:
            self.raw_data = ()

    def has_file(self):
        """Return ``True`` if ``self.data`` is a
        :class:`~werkzeug.datastructures.FileStorage` object.
        .. deprecated:: 0.14.1
            ``data`` is no longer set if the input is not a non-empty
            ``FileStorage``. Check ``form.data is not None`` instead.
        """

        warnings.warn(FlaskWTFDeprecationWarning(
            '"has_file" is deprecated and will be removed in 1.0. The data is '
            'checked during processing instead.'
        ))
        return bool(self.data)

As you can see, the class inherits from the standard wtforms implementation (named _FileField in the module) but extends it to override the process_formdata() method and add the has_file() method.

Also note that they are depreciating the method and suggest that you just check the data attribute of the field instead - its not exactly a technical implementation so you can just do what they do to get the same functionality: bool(field.data).

For reference, here is the wtforms FileField implementation:

class FileField(Field):
    """Renders a file upload field.
    By default, the value will be the filename sent in the form data.
    WTForms **does not** deal with frameworks' file handling capabilities.
    A WTForms extension for a framework may replace the filename value
    with an object representing the uploaded data.
    """

    widget = widgets.FileInput()

    def _value(self):
        # browser ignores value of file input for security
        return False

...which shows that it doesn't have any methods beyond those defined on the base Field class.

Upvotes: 3

Related Questions