I'm having problems with wtforms selectfields

2019-02-08 00:07发布

I'm pretty new to wtforms and flask and was messing around with selectfields and got an error. The form itself works just fine without the selectfield but with it I get the following error:

Error:

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

I see the selectfield so it's being rendered. I suspect somehow the id is not being validated properly on POST and is returning none. Or it has something to do with my selectfield tuple being returned ? Also the ID field I'm using is pulled from GAE's ndb automatic key().id() which is rather long and obnoxious. It could be the id length being used for the selectfield is too long ?

Googling hasn't provided much in terms of the exact problem so thought I'd post here. Relevant code below. If I'm missing something please let me know

views.py code:

@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 %}

2条回答
beautiful°
2楼-- · 2019-02-08 00:49

You need to set your choices before you call validate_on_submit as form.validate will attempt to validate the provided value (if any) against the list of choices (which is None before you set 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
查看更多
冷血范
3楼-- · 2019-02-08 01:08

You should provide choices=[...] argument, like

wtf.SelectField(u'Home Name List',
                choices=[(1, 'Label 1'),
                         (2, 'Label 2')],
                coerce=int,
                validators=[validators.optional()])
查看更多
登录 后发表回答