FileRequiredValidator() doesn't work when using MultipleFileField() in my form
Asked Answered
O

3

8

My UploadForm class:

    from app import app
    from flask_wtf.file import FileRequired, FileAllowed
    from wtforms.fields import MultipleFileField
    from wtforms.validators import InputRequired,DataRequired
  class UploadForm(FlaskForm):
     .
     .
     .
     roomImage = MultipleFileField('Room',validators=[FileAllowed(['jpg', 'png'], 'Image only!'), FileRequired('File was empty!')] )
     .
     .
     .#there are other fields here which are  not relevant to  the problem at hand

HTML Template

{% extends "base.html" %}

{% block content %}
 <h1>Upload Your Images</h1>
<form  action="/" enctype="multipart/form-data" method="post"  >
    {{ form.csrf_token }}
    Room<br />
    {{form.roomImage()}}
    .
    .
    . <MORE THINGS THAT I HAVE EDITED OUT>
    {{form.submit()}}
    <br/>
    {% if form.errors %}
      {{ form.errors }}
    {% endif %}
</form>
{% endblock %}

hosts.py to run the check for validation

def upload_image():#NEEDS HEAVY FIXING
    """home page to return the web page to upload documents"""
    form = UploadForm()
    if form.validate_on_submit():

Using VS's debugging tools, I find that form.validate_on_submit() doesn't work and always fails validation and I get this error on my html page.

{'roomImage': ['File was empty!']}

There is another MultipleFileField control with almost the exact same code. This issue does not happen when I use FileField to upload one file. The documentation on this is very limited and all I had to go on was this. I don't really know how to solve this issue. I have searched extensively for finding example involving MultipleFileField but they are not using any validation. A thread on Github that I can't find anymore suggested using OptionalValidator, but then that is not an option for me and even that didn't work. Can someone suggest me a solution?

EDIT:

Even the FileAllowed() validator does not seem to work.

Oops answered 14/1, 2020 at 12:59 Comment(0)
M
2

This works for me (found on GitHub "between the lines"):

multi_file = MultipleFileField("Upload File(s)", validators=[DataRequired()])

However

FileAllowed(["xml", "jpg"])

is ignored and does not work for me.

EDIT: No, sadly, it does not work... It returns True for form.validate() and for form.validate_on_submit() but when you pass no files, by deleting

required=""

from

<input id="multi_file" multiple="" name="multi_file" required="" type="file">

and submit a form, it still evaluate that as True.

So problem sill persist in full, as described...

Mattoid answered 27/1, 2020 at 21:46 Comment(1)
Created an issue on their GitHub project. github.com/lepture/flask-wtf/issues/393 drop in your two cents if you feel like it.Neral
C
1

Regarding FileAllowed validator , it is not working because FileAllowed validator expect one FileStorage object , but MultipleFileField is sending a list of Filestorage objects , which is why it is not working . You have to implement a MultiFileAllowed validator yourself. For More details StackOverflow answer explained with example.

Cholula answered 21/7, 2020 at 8:31 Comment(2)
I created a custom validation class, which worked fine for me.Oops
As for FileAllowed, I had only used it cause the thread on Github had mentioned it. It was not the one I needed for my use case. My use case was to work on performing the validation of the file being uploaded.Oops
O
0

This approach seems to solve the one part of the problem and it uses j-query, which I was unfamiliar with until this point. So since I am a novice when it comes to web-dev, I was looking for a python based approach to this one. I don't think it exists just yet. Will update when I fix the multiple file upload issue. Jsfiddle link

jQuery.validator.setDefaults({
  debug: true,
  success: "valid"
});
$( "#myform" ).validate({
  rules: {
    ":file": {
      required: true,
      accept: "image/*"
    }
  }
});

and

<form id="myform">
<label for="field">Required, image files only: </label>
<input type="file" class="left" id="field" name="field" multiple>
<br/>
<input type="submit" value="Validate!">
</form>
<script src="https://code.jquery.com/jquery-1.11.1.min.js"></script>
<script src="https://cdn.jsdelivr.net/jquery.validation/1.16.0/jquery.validate.min.js"></script>
<script src="https://cdn.jsdelivr.net/jquery.validation/1.16.0/additional-methods.min.js"></script>

Since I was using wtforms, I tried something called a validation class and inline validators that seems to do the trick.

 """
Validation Class for RoomUpload
"""
class MyRoomValidator(object):
    def __init__(self, message=None):
        if not message:
            message = u"You need to upload the images with the category as well"
        self.message = message

    def __call__(self, form, field):
        print(len(form.roomImage.data))
        print((form.roomTypeSelect.data))
        if (not form.roomImage.data and  form.roomTypeSelect.data == -1) or(form.roomImage.data and  form.roomTypeSelect.data == -1) or (not form.roomImage.data and  form.roomTypeSelect.data != -1):#check for all possible combinations
            raise ValidationError(self.message)

class RoomUpload(FlaskForm):
    """
    This is meant for the sub-form for room details upload
    containing the details for room and its subtype

    roomImage:Upload the room image
    roomTypeSelect:The subcategory for room category

    The Form will only be submitted if the images  are uploaded and
    the RoomType will be selected
    """
    def validate_roomTypeSelect(form, field):#Inline Validator to ensure if default choice is not chosen
       print(field.data)
       if field.data == -1:
            raise ValidationError('Need to Select Room Type')
    def validate_roomImage(form,field):
        for roomFile in field.data:
            print(roomFile.filename)
            if  isanImageFile(roomFile.filename) == False: 
                raise ValidationError("Error!!! Not an Image File ")
    roomImage = MultipleFileField(u"Room",validators=[MyRoomValidator(),FileAllowed],id = "roomImage")
    roomTypeSelect= SelectField("Room Type",choices=roomTypes,coerce=int,id="roomTypeSelect")
    roomSubmit = SubmitField("Upload the images  of the room")
Oops answered 16/1, 2020 at 8:7 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.