title: Passing Flask WTForms validations to Bootstrap Alerts via Flask-Bootstrap
body: <p>new Flask user here...I am building a pretty file upload button for my flask app. The button essentially makes use of WTForms to validate that only csv and txt files can be uploaded. The upload works, but how can I pass validation errors to the screen as a bootstrap alert?  For example:</p>
  
  <ol>
  <li>pressing the upload button will generate an alert "no file selected"</li>
  <li>pressing upload with a jpeg will generated "wrong file format"</li>
  </ol>
  
  <p>any suggestions will be appreciated!</p>
  
  <p>My forms.py:</p>
  
  <pre><code>class UploadForm(FlaskForm):
      validators = [FileRequired(message='There was no file!'),
                    FileAllowed(['csv', 'txt'], message='Must be a csv file!')]
  
      input_file = FileField('', validators=validators)
      submit = SubmitField(label="Upload")
  </code></pre>
  
  <p>my route.py:</p>
  
  <pre><code>@app.route('/upload', methods=['GET', 'POST'])
  def upload():
  
      form = UploadForm()
  
      if request.method == 'POST' and form.validate_on_submit():
          input_file = request.files['input_file']
  
          # Do stuff
          filename = secure_filename(input_file.filename)
  
          # save file to disk to some folder defined in a separate config file....
          data = os.path.join(SOME_UPLOAD_FOLDER, filename)
          input_file.save(data)
  
          return redirect(url_for('upload'))
  
  else:
      return render_template('upload.html', form=form)
  </code></pre>
  
  <p>and finally the HTML/CSS/JS:</p>
  
  <pre><code>{% extends "bootstrap/base.html" %}
  {% import "bootstrap/wtf.html" as wtf %}
  
  {% block html_attribs %} lang="en" charset="utf-8"{% endblock %}
  
  {% block metas %}
      &lt;meta charset="utf-8"&gt;
      &lt;meta http-equiv="X-UA-Compatible" content="IE=edge"&gt;
  {% endblock %}
  
  
  {% block styles %}
  
      &lt;!-- Latest compiled and minified CSS --&gt;
      &lt;link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css"
            integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous"&gt;
  
      &lt;style&gt;
          #browsebutton {
              background-color: white;
          }
  
          #my-file-selector {
              display: none;
          }
      &lt;/style&gt;
  
  
  {% endblock %}
  
  {% block content %}
  
      &lt;div class="container"&gt;
          &lt;div class="jumbotron"&gt;
              &lt;h3&gt;File Uploader Example&lt;/h3&gt;
  
  
              &lt;div class="row"&gt;
                  &lt;form class="form-inline center-block" action="/upload" method="POST" enctype="multipart/form-data"&gt;
                      {{ form.hidden_tag() }}
                      &lt;div class="input-group"&gt;
                          &lt;label id="browsebutton" class="btn btn-default input-group-addon" for="my-file-selector"&gt;
                              {{ form.input_file(id="my-file-selector") }}
                              Browse...
                          &lt;/label&gt;
                          &lt;input type="text" class="form-control" readonly&gt;
                      &lt;/div&gt;
                      {{ form.submit(class_="btn btn-primary") }}
                  &lt;/form&gt;
              &lt;/div&gt;
          &lt;/div&gt;
      &lt;/div&gt;
  
  {% endblock %}
  
  
  {% block scripts %}
  
      &lt;! -- jquery --&gt;
      &lt;script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"&gt;&lt;/script&gt;
      &lt;!-- Latest compiled and minified JavaScript --&gt;
      &lt;script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"
              integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa" crossorigin="anonymous"&gt;&lt;/script&gt;
  
      &lt;!-- pretty upload button --&gt;
      &lt;script&gt;
      $(function() {
  
        // We can attach the `fileselect` event to all file inputs on the page
        $(document).on('change', ':file', function() {
          var input = $(this),
              numFiles = input.get(0).files ? input.get(0).files.length : 1,
              label = input.val().replace(/\\/g, '/').replace(/.*\//, '');
          input.trigger('fileselect', [numFiles, label]);
        });
  
        // We can watch for our custom `fileselect` event like this
        $(document).ready( function() {
            $(':file').on('fileselect', function(event, numFiles, label) {
  
                var input = $(this).parents('.input-group').find(':text'),
                    log = numFiles &gt; 1 ? numFiles + ' files selected' : label;
  
                if( input.length ) {
                    input.val(log);
                } else {
                    if( log ) alert(log);
                }
  
            });
        });
  
      });
      &lt;/script&gt;
  
  {% endblock %}
  </code></pre>