Search code examples
javascriptjsonajaxflaskflask-wtforms

upload image using flask and ajx (alwys empty form data)


i am new in Flask and try to upload images using ajax and form data and I always get form data sent as empty filed and my function always gets stuck in a validation error as filed is required even i click and send the image inside form,i need some one to help me to solve this issue.i see more solution and dint got the issue.

my code here

@presentation.route('/presentation/updateImage',methods=['POST'])
@login_required
def updateImage() :

    UpdateImageForm = UpdateImage(request.form)
    if  UpdateImageForm.validate_on_submit() :
        
        image        = request.json.get("image")
        print(image)
        return jsonify({'status': "success", 'message': 'Password Changed Successfuly','id':image})               
    else:   
        errors = {}
        for field, field_errors in UpdateImageForm.errors.items():
            errors[field] = [str(error) for error in field_errors]
        return jsonify({'status': "errors ", 'message': errors})   

my form is :

                    <div class="modal fade" id="update-img" tabindex="-1" aria-hidden="true">
                      <div class="modal-dialog modal-dialog-centered1 modal-simple modal-add-new-cc">
                        <div class="modal-content p-3 p-md-5">
                          <div class="modal-body">
                            <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
                            <div class="text-center mb-4">
                              <h3 class="mb-2">Change Image</h3>
                           
                            </div>
                            <form id="updateImage"  method="POST" class="row g-3" enctype="multipart/form-data">
                                {{UpdateImageForm.hidden_tag()}}
                              <label class="form-label" for="bs-validation-upload-file">Presntaion  Images</label>
                              <div class="mb-3">
                                {{ UpdateImageForm.image(class_="form-control") }}<br>

                              </div>

               
                            
                              <div class="col-12 text-center">
                                <button type="submit" class="btn btn-primary me-sm-3 me-1">Submit</button>
                                <button
                                  type="reset"
                                  class="btn btn-label-secondary btn-reset"
                                  data-bs-dismiss="modal"
                                  aria-label="Close">
                                  Cancel
                                </button>
                              </div>
                            </form>
                          </div>
                        </div>
                      </div>
                    </div>

js code :

  // start edit image
  $(".table_for_data").on( 'click', '.editImage', function () {
    $("#updateImageResult").html("");
    // get id for update
    var myId = $(this).attr("data-id");
   // alert(myId)
    $("#updateImage").submit(function(e){
      e.preventDefault()
    var form_data = new FormData($('#updateImage')[0]);
        $.ajax({
          url: "{{ url_for('presentation.updateImage') }} ",
            type: "POST",
            data: JSON.stringify(form_data),                
            contentType: 'application/json',                 
            beforeSend:function(){
                $(".loadingImage").show();
            },
            statusCode: {
                404: function() {
                    alert( "page not found" );
                },
            },
            success:function(valdata) {
              alert('success')
             
            }
        });
        return false;
    });
});

Solution

  • Basically, you should decide whether you want to send form data or JSON. If you want to send files, the former is recommended. A combination of both fails.

    The following example shows you how to send the entire form to the server via AJAX.
    On the server side, the form is initialized without request.form because files are not contained within this dictionary.

    from flask import (
        Flask, 
        abort, 
        render_template 
    )
    from flask_wtf import FlaskForm
    from flask_wtf.file import FileField, FileAllowed, FileRequired
    
    app = Flask(__name__)
    app.secret_key = 'Your secret here!' 
    
    class UpdateImageForm(FlaskForm):
        image = FileField(validators=[
            FileRequired(), 
            FileAllowed(['jpg', 'png'], 'Images only!')
        ])
    
    @app.route('/update')
    def index():
        form = UpdateImageForm()
        return render_template('index.html', **locals())
    
    @app.post('/update')
    def update():
        form = UpdateImageForm()
        if form.validate():
            print(form.image.data)
            return '', 200
        abort(400)
    

    Please note that the content type is not set and the data is not processed. Only then will the form be sent in the "multipart/form-data" format, as required to upload a file.

    <!DOCTYPE html>
    <html>
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Index</title>
    </head>
    <body>
        <form name="my-form">
            {{ form.hidden_tag() }}
            {{ form.image() }}
            <button type="submit">Update</button>
        </form>
    
        <script 
            src="https://code.jquery.com/jquery-3.7.1.min.js" 
            integrity="sha256-/JqT3SQfawRcv/BIHPThkBvs0OEvtFFmqPF/lYI/Cxo=" 
            crossorigin="anonymous"></script>
        <script>
            (function() {
    
                $('form[name="my-form"]').submit(function(event) {
                    event.preventDefault();
                    $.ajax({
                        url: {{ url_for('update') | tojson }}, 
                        type: 'POST', 
                        data: new FormData(this), 
                        cache: false,
                        contentType: false,
                        processData: false,
                    }).done(() => {
                        console.log('Image uploaded successfully.');
                    })
                });
    
            })();
        </script>
    </body>
    </html>