Форма не проверяется. csrf_token включен - PullRequest
0 голосов
/ 22 апреля 2020

У меня есть следующая проблема с методом validate_on_submit () в моем приложении Flask.

Быстрый обзор того, что у меня есть:

Мой класс формы создается динамически на основе ввода:

class EditUsers(FlaskForm):

    submit = SubmitField('Submit')

def form_builder(roles_list):

    class EditUsersForm(EditUsers):
        pass

    for role in roles_list:
        if isinstance(role, tuple) and len(role) == 5:
            if not role[2] and role[3]:
                setattr(EditUsersForm, f'{role[0]}_{role[4]}_bool', BooleanField(label=role[0]))
                setattr(EditUsersForm, f'{role[0]}_{role[4]}_date', SelectField('Expiration Period', choices=choices))
        else:
            raise IncorrectType

Неверный тип - это пользовательское Исключение, которое я подготовил, и варианты создаются с использованием даты и времени в том же файле (это не имеет значения, поэтому я не включаю его в код).

Мой маршрут в приложении flask (упрощено) ):

#### EDIT: I pasted the wrong route, POST and GET Methods are included###
@edit_users.route('/users', methods=['GET', 'POST'])

def users():
...  # Some code there
form = form_builder(roles_to_form)

print(form.is_submitted())
print(form.validate())
print(form.validate_on_submit())

return render_template('edit_user.html',
                       data_dict=data_dict,  # in data_dict i pass form fields names and some other data
                       form=form,
                       )

Мой шаблон:

<!-- Some usual stuff goes there css js etc -->

<div >
    <form class="form form-horizontal" method="post" role="form" style="margin: auto; text-align: center; width: 40%;">
        {{ form.csrf_token() }}
        <table class="table" align="center">
            <thead>
                <th>Role</th>
                <th>Expiration Date</th>
                <th>Give Role?</th>
            </thead>
            {% for field in data_dict['id_list'] %}
            <tr>
                <td align="left">{{ field[2] }}</td>
                <td align="left">
                    {{ form[field[1]] }}
                </td>
                <td align="left">{{ form[field[0]] }}</td>
            </tr>
            {% endfor %}
            <tr>
                <td colspan="3" align="center">{{ form.submit() }}</td>
            </tr>
        </table>
    </form>
</div>

В чем моя проблема?

Когда я нажимаю кнопку подтверждения, is_submitted() возвращает True, но validate() нет, поэтому я не могу использовать типичный if form.validated_on_submit(), поскольку он возвращает False, даже когда я отправляю свою форму.

Я немного копаю и замечаю что-то необычное. Я использовал защищенные члены атрибутов формы, чтобы проверить, какую функцию validate () видит в качестве ввода:

for name in form._fields:
    print(name)
    inline = getattr(form.__class__, 'validate_%s' % name, None)
    print(inline)

Вывод (не обращая внимания на имена полей):

submit

Нет

Engineer_2_bool

Нет

Engineer_2_date

Нет

Operator_3_bool

Нет

Operator_3_date

Нет

Supervisor_4_bool

Нет

Supervisor_4_date

Нет

Guest_5_bool

Нет

Гость_5_дата

Нет

csrf_token

Нет

Я не знаю, почему моя форма не имеет validate_{name} атрибутов.

Ответы [ 2 ]

1 голос
/ 22 апреля 2020

Я сделал рабочий пример из вашего кода и в итоге столкнулся с проблемой, которую вы описали.

Если я полностью изменил ваш код, кажется, что form[field[1]] - это ваш BooleanField или SelectField. Поэтому для рендеринга в шаблоне вам нужно использовать form[field[1]]() (также можно использовать render_field). Итак:

<tr>
    <td align="left">{{ field[2] }}</td>
    <td align="left">
        {{ form[field[1]] }}
    </td>
    <td align="left">{{ form[field[0]] }}</td>
</tr>

исправлено на:

<tr>
    <td align="left">{{ field[2] }}</td>
    <td align="left">
        {{ form[field[1]]() }}
    </td>
    <td align="left">{{ form[field[0]]() }}</td>
</tr>

https://flask.palletsprojects.com/en/1.1.x/patterns/wtforms/#forms -в-шаблонах

Поскольку вы используете FlaskForm, в вашем шаблоне вы должны заменить {{ form.csrf_token() }} на {{ form.csrf_token }} https://flask-wtf.readthedocs.io/en/stable/csrf.html#html -forms [EDIT не имеет никакого значения]

[Отредактировано после комментария w8eight] Маршрут не авторизован для POST (и форма отправляет запрос POST, как показано в <form class="form form-horizontal" method="post" [...]. Поэтому вы должны изменить: @edit_users.route('/users', methods=['GET']) на @edit_users.route('/users', methods=['GET','POST'])

0 голосов
/ 26 апреля 2020

Проблема была с типом данных, переданных на выбор SelectField. Я передал ему список кортежей с datetime.datetime. При изменении типа на str все работает плавно.

...