У меня проблемы с полями выбора wtforms, когда я использую POST с Flask

Я новичок в wtforms и flask, возился с selectfields и получил ошибку. Сама форма отлично работает без поля выбора, но с ним я получаю следующую ошибку:

Ошибка:

....fields.py", line 386, in pre_validate
    for v, _ in self.choices: TypeError: 'NoneType' object is not iterable

Я вижу поле выбора, поэтому оно отображается. Я подозреваю, что каким-то образом идентификатор не проверяется должным образом на POST и ничего не возвращает. Или это как-то связано с моим возвращаемым кортежем selectfield? Также поле идентификатора, которое я использую, взято из автоматического ключа GAE ndb().id(), который довольно длинный и неприятный. Возможно, длина идентификатора, используемого для поля выбора, слишком велика?

Гугление не дало многого с точки зрения точной проблемы, поэтому решил опубликовать здесь. Соответствующий код ниже. Если я что-то упустил, пожалуйста, дайте мне знать

Код view.py:

@app.route('/new/post', methods = ['GET', 'POST'])
@login_required
def new_post():

    form = PostForm()
    if form.validate_on_submit():
        post = Post(title = form.title.data,
                    content = form.content.data,
                    hometest = form.hometest.data,
                    author = users.get_current_user())
        post.put()
        flash('Post saved on database.')
        return redirect(url_for('list_posts'))
    form.hometest.choices = [ (h.key.id(),h.homename)for h in Home.query()]

    return render_template('new_post.html', form=form)

myforms.py:

class PostForm(Form):
    title = wtf.TextField('Title', validators=[validators.Required()])
    content = wtf.TextAreaField('Content', validators=[validators.Required()])
    hometest = wtf.SelectField(u'Home Name List', coerce=int,validators=[validators.optional()])

new_post.html:

{% extends "base.html" %}

{% block content %}
    <h1 id="">Write a post</h1>
    <form action="{{ url_for('new_post') }}" method="post" accept-charset="utf-8">
        {{ form.csrf_token }}
        <p>
            <label for="title">{{ form.title.label }}</label><br />
            {{ form.title|safe }}<br />
            {% if form.title.errors %}
            <ul class="errors">
                {% for error in form.title.errors %}
                <li>{{ error }}</li>
                {% endfor %}
            </ul>
            {% endif %}
        </p>
        <p>
            <label for="title">{{form.hometest.label}}</label><br/>
            {{form.hometest}}
            {% if form.hometest.errors %}
        <ul class="errors">
            {% for error in form.hometest.errors %}
            <li>{{ error }}</li>
            {% endfor %}
        </ul>
        {% endif %}
        </p>
        <p>
            <label for="title">{{ form.content.label }}</label><br />
            {{ form.content|safe }}<br />

            {% if form.content.errors %}
            <ul class="errors">
                {% for error in form.content.errors %}
                <li>{{ error }}</li>
                {% endfor %}
            </ul>
            {% endif %}
        </p>
        <p><input type="submit" value="Save post"/></p>
    </form>
{% endblock %}

person prussiap    schedule 10.04.2013    source источник


Ответы (2)


Вам нужно задать варианты выбора до вызова validate_on_submit, так как form.validate попытается проверить предоставленное значение (если есть) по списку вариантов (который None до того, как вы установите choices):

form = PostForm()
form.hometest.choices = [(h.key.id(), h.homename) for h in Home.query()]

if form.validate_on_submit():
    # form is valid, continue
person Sean Vieira    schedule 11.04.2013
comment
Как вы можете пропустить определенное поле, если вы не хотите проверять его? Я получаю сообщение об ошибке для поля даты с validators=[validators.Optional()] - person vivekanon; 13.05.2016
comment
Стоит задать отдельный вопрос об этом с минимальным воспроизводимым примером. Кто-то должен помочь :-) - person Sean Vieira; 13.05.2016
comment
Это именно моя проблема, которая решена этим ответом. - person shgnInc; 18.12.2018
comment
Большое спасибо ! Я боролся с той же проблемой. Перемещение myform.choices= независимо от того, что ДО form.validate_on_submit() исправлено! - person Miguel Rozsas; 13.02.2020
comment
О, спасибо ! Я разбираюсь с этой ошибкой уже час, это точно решение моей проблемы! - person Teazane; 16.06.2020

Вы должны предоставить аргумент choices=[...], например

wtf.SelectField(u'Home Name List',
                choices=[(1, 'Label 1'),
                         (2, 'Label 2')],
                coerce=int,
                validators=[validators.optional()])
person seriyPS    schedule 10.04.2013
comment
Похоже, вы на самом деле не можете использовать аргумент выбора в selectField для динамического выбора, как показано в документации, wtforms.readthedocs.io/en/latest/…, потому что даже если ваш аргумент выбора в поле выбора является запросом, как в wtf.SelectField(u'Home Name List', choices=[(h.key.id(), h.homename) for h in Home.query()], coerce=int) этот запрос не запускается каждый раз, когда отображается форма.. поэтому динамически добавляемые экземпляры дома не будут отображаться в раскрывающемся списке.. из того, что я тестировал - person ; 29.11.2016