WTForms Ajax验证失败

I'm building my first web application in Python and am making the application more dynamic.

The code is working properly as long as the user is filling the correct data. However I am testing now some erroneous input and there is where it fails. I am using WTForms and while building the non-ajax pages everything was working fine, the application gave the front end a nice "Invalid input" when the user put wrong data in there. Now the application breaks.

This is the Form:

class ExpenseForm(FlaskForm):
    list_id = HiddenField(validators=[DataRequired()])
    title = StringField('Expense', validators=[DataRequired()])
    expensetype_id = SelectField('Expense Type', coerce=int)
    price = DecimalField('Cost', places=2, validators=[DataRequired()])
    quantity = IntegerField('Quantity', validators=[DataRequired()])
    currency_id = SelectField('Currency', coerce=int)
    country_id = SelectField('Country', coerce=int)
    city = StringField('City', validators=[DataRequired()])
    date = DateField('Date', validators=[DataRequired()])
    exceptional_cost = BooleanField('Exceptional cost')
    submit = SubmitField('Add')

My route:

@bp.route('/commit_expense', methods=['POST'])
@login_required
def commit_expense():
    form = ExpenseForm()
    form.expensetype_id.choices = [(et.id, et.name) for et in Expensetype.query.order_by('name')]
    form.currency_id.choices = [(c.id, c.short) for c in Currency.query.order_by('short')]
    form.country_id.choices = [(co.id, co.name) for co in Country.query.order_by('name')]
    print(form.data)
    if form.validate_on_submit():
        extra_add_expense(form)
        return jsonify({'success': 'Expense added'})
    return jsonify({'error':'Failed to add expense',
                        'form_errors':[{form[field].label: ', '.join(errors)} for field, errors in form.errors.items()]})

And the javascript:

$(function () {
    $("#expense_form").submit(function (event) {
        event.preventDefault(); // Prevent the form from submitting via the browser
        var form = $(this);
        var error_div = $("#form_errors");
        $(error_div).children().remove();
        $.ajax({
            type: form.attr('method'),
            url: form.attr('action'),
            data: form.serialize()
        }).done(function (data) {
            if (data.error) {
                for (item in data.form_errors) {
                    Object.keys(data.form_errors[item]).forEach(function (key) {
                        $('<p>').text(key + ': ' + data.form_errors[item][key]).addClass("show_error").appendTo(error_div);
                    });
                };
            } else {
                form[0].reset();
                daily_refresh();
            }
        }).fail(function (data) {
            // Finish fail here
        });
    });
});

So as long as I fill in the correct information in all fields, everything passes as it should, but the moment I fill in some wrong information, for the price for example, I get this:

TypeError: key Label('price', 'Cost') is not a string

The example json message is:

list_id=2&csrf_token=IjA0NGJjNzU1Nzg3ODg1ZjhhODQ0YzE5ODMwYzkzZTBkNjEyMWQyYjIi.Du1lBg.nJJpKiNSV4pnCLsIfzUaqlsmscg&title=ff&expensetype_id=1&price=f&quantity=1&currency_id=2&city=GHanzhaou&country_id=5&date=2018-12-08

Then I get the following data from the print(form.data):

{'list_id': '2', 'title': 'ff', 'expensetype_id': 1, 'price': None, 'quantity': 1, 'currency_id': 2, 'country_id': 5, 'city': 'GHanzhaou', 'date': datetime.date(2018, 12, 8), 'exceptional_cost': False, 'submit': False, 'csrf_token': 'IjA0NGJjNzU1Nzg3ODg1ZjhhODQ0YzE5ODMwYzkzZTBkNjEyMWQyYjIi.Du1lBg.nJJpKiNSV4pnCLsIfzUaqlsmscg'}

Now I have tested this against my other non-ajax functions and they also seem to have a 'None' when the data is incorrect (with other DecimalFields for example). At the point of validation they just return the 'DataRequired' error and the page handles the display.

I don't quite see the reason behind this failing. Any help or insight is highly appreciated.

Thanks in advance!

form[field].label is a Label instance, not string.

Use form[field].label.text to get the string representation of the label.

The last line of your view should be

 return jsonify({'error':'Failed to add expense',
                 'form_errors':[{form[field].label.text: ', '.join(errors)} for field, errors in form.errors.items()]})