Reputation: 119
I am trying to use a single form that has numerous fields, including FileFields populated from Flask-WTForms. When the form is posted, it does not include any of the data. The form works when the attachment : form_data,
is not included. (It worked before submitting regular fields, however now I've been trying all day to add file uploading with no success).
My form is as follows:
<form class="form-horizontal" enctype="multipart/form-data">
<div class="form-group">
<label class="col-sm-2 control-label">Material Description</label>
<div class="col-sm-10">
{{ form2.description(placeholder='Material Description', class='form-control') }}
</div>
</div>
<div class="form-group">
<label class="col-sm-2 control-label">Cost</label>
<div class="col-sm-10">
{{ form2.cost(placeholder='Cost', class='form-control') }}
</div>
</div>
<div class="form-group">
<label class="col-sm-2 control-label">Quantity</label>
<div class="col-sm-10">
{{ form2.quantity(placeholder='Quantity', class='form-control') }}
</div>
</div>
<div class="form-group">
<label class="col-sm-2 control-label">Used</label>
<div class="col-sm-10">
{{ form2.used(placeholder='Used', class='form-control') }}
</div>
</div>
<div class="form-group">
<label class="col-sm-2 control-label">Supplier</label>
<div class="col-sm-10">
{{ form2.supplier(class='form-control') }}
</div>
<div class="form-group">
<label class="col-sm-2 control-label">Attachment</label>
<div class="col-sm-10">
{{ form2.attachment(class='form-control') }}
</div>
</div>
{{ form1.hidden_tag() }}
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<button id="materialsButton" type="submit" class="btn btn-default">Add Materials</button>
</div>
</div>
</form>
My endpoint handler:
@app.route('/api/submit_materials', methods=['POST'])
def submit_materials_api():
form = MaterialsForm()
form.workorder_id.choices = [(work.id, work.id) for work in Workorder.query.order_by(desc('id'))]
if form.validate_on_submit():
workorder_id = form.workorder_id.data
workorder = Workorder.query.filter_by(id = workorder_id).first_or_404()
description = form.description.data
cost = form.cost.data
quantity = form.quantity.data
used = form.used.data
supplier = form.supplier.data
attachment_filename = secure_filename(form.attachment.file.filename)
form.attachment.file.save('static/attachments/' + str(workorder_id) + '_' + attachment_filename)
materials = Materials(description, cost, quantity, used, supplier, attachment_filename)
workorder.work_order_materials.append(materials)
db.session.add(materials)
db.session.commit()
return jsonify({'materials' : materials.description, 'workorder_id' : workorder_id, 'quantity' : quantity})
else:
for field, errors in form.errors.items():
for error in errors:
error_data = (u"Error in the %s field - %s" % (getattr(form, field).label.text, error))
return jsonify({'error' : error_data})
And what I believe is the culprit, my JS / jQuery:
$('#materialsButton').click(function (e) {
var form_data = new FormData($('#attachment')[0]);
$.ajax({
type : "POST",
dataType :"json",
url : "/api/submit_materials",
data : {
workorder_id : data.workorder_id,
description : $('#description').val(),
cost : $('#cost').val(),
quantity : $('#quantity').val(),
used : $('#used').val(),
supplier : $('#supplier').val(),
attachment : form_data,
},
contentType : false,
cache : false,
processData : false,
success: function (data) {
if (data.error) {
$("#errorAlert").text(data.error).show();
$("#successAlert").hide();
}
else {
$("#successAlert").text(data.quantity + ' of ' + data.materials + ' successfully added to workorder MCI' + data.workorder_id + '. You may submit additional materials or hours below.').show();
$("#errorAlert").hide();
$("#materialsForm").trigger("reset");
$("#hoursForm").fadeIn("slow");
}
}
});
e.preventDefault();
To save space this is only a portion of the entire JS script.
Upvotes: 0
Views: 159
Reputation: 1761
you have to serialize the formData before sending to server side. Set a id to your form.
<form class="form-horizontal" enctype="multipart/form-data" id="matarialsForm">
Then use this jquery.
$('#materialsButton').click(function (e) {
e.preventDefault();
var formData = new FormData();
var stringData = $('#matarialsForm form').serializeArray();
$.each(stringData,function(key,input){
formData.append(input.name,input.value);
});
$.ajax({
type : "POST",
dataType :"json",
url : "/api/submit_materials",
data : formData
contentType : false,
cache : false,
processData : false,
success: function (data) {
if (data.error) {
$("#errorAlert").text(data.error).show();
$("#successAlert").hide();
}
else {
$("#successAlert").text(data.quantity + ' of ' + data.materials + ' successfully added to workorder MCI' + data.workorder_id + '. You may submit additional materials or hours below.').show();
$("#errorAlert").hide();
$("#materialsForm").trigger("reset");
$("#hoursForm").fadeIn("slow");
}
}
});
Upvotes: 0
Reputation: 97672
When using a formdata object in an ajax request the data field must be the formdata object.
$.ajax({
...
data : form_data,
...
});
Also, the formdata constructor takes a form not a field
var form_data = new FormData(this.form);
This will add all the fields in the form to the formdata object, then use append()
for the rest of data
form_data.append('workorder_id', data.workorder_id);
Upvotes: 1