Как выполнить проверку формы Flask WTForms, если форма частично сформирована на стороне клиента - PullRequest
2 голосов
/ 31 мая 2019

Я строю простой пользовательский интерфейс с двумя выпадающими списками.Основываясь на том, что выбрано в первом раскрывающемся списке, второй раскрывающийся список заполняется некоторыми новыми значениями через jquery / AJAX.Проблема заключается в том, что при отправке формы проверка формы по ошибке завершается ошибкой, поскольку во втором возвращающемся раскрывающемся списке отсутствует параметр, который был создан в первом списке.

Я получил егоработать, вводя все данные, которые были отправлены из выпадающего списка 2 в объект формы, прежде чем проверять форму.Этот код показан ниже, но выглядит как хакерское решение.

form = SearchForm(request.form)

# dropdown 1
form.node_type.choices = [('default', 'Please select a node type')]
form.node_type.choices.extend([(t, t) for t in node_types()])

# dropdown 2
form.node_name.choices = [('default', 'Select a node type first')]

if request.method == 'POST':
    # the below 2 lines are the hack that make it work.
    node_name = request.form.get('node_name')
    form.node_name.choices.append((node_name, node_name))

    if form.validate():
        print('hooray')

Существует ли стандартный / рекомендуемый способ динамического добавления параметров на стороне клиента и при этом WTForms правильно выполняют проверку формы?

1 Ответ

2 голосов
/ 01 июня 2019

Это чистое решение wtforms, но оно должно работать с flask-wtf (flask-wtf вызывает form.validate() в пределах form.validate_on_submit()).

Код расширяется Form.validate для вызова пользовательской функции проверки, если поле node_name не прошло проверку с ошибкой «Неправильный выбор». Если функция проверки возвращает True, она удаляет ошибку «Неправильный выбор» из Form.errors и возвращает True, если Form.errors теперь пусто.

import werkzeug
import wtforms


class Form(wtforms.Form):

    node_type = wtforms.SelectField(choices=[(x, x) for x in 'ABCDEF'])
    node_name = wtforms.SelectField(choices=[('', '')])

    def validate(self):
        if super().validate():
            return True
        invalid_choice = 'Not a valid choice'
        if 'node_name' in self.errors and invalid_choice in self.errors['node_name']:
            is_valid_node_name = self.cross_validate_node_name()
            if is_valid_node_name:
                self.errors['node_name'].remove(invalid_choice)
                if not self.errors['node_name']:
                    del self.errors['node_name']
                return not self.errors
        return False

    def cross_validate_node_name(self):
        # Implement your validation logic here.
        return self.node_type.data == 'B' and self.node_name.data == 'spam'


if __name__ == '__main__':
    datas = [werkzeug.MultiDict([('node_type', 'A'), ('node_name', 'spam')]),
             werkzeug.MultiDict([('node_type', 'B'), ('node_name', 'spam')])]
    for data in datas:
        form = Form(formdata=data)
        if form.validate():
            print('OK')
        else:
            print(form.errors)
...