Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

I'm having problems with wtforms selectfields when i use a POST with Flask

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 %}
like image 208
prussiap Avatar asked Apr 10 '13 21:04

prussiap


2 Answers

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
like image 92
Sean Vieira Avatar answered Oct 22 '22 11:10

Sean Vieira


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

wtf.SelectField(u'Home Name List',
                choices=[(1, 'Label 1'),
                         (2, 'Label 2')],
                coerce=int,
                validators=[validators.optional()])
like image 26
seriyPS Avatar answered Oct 22 '22 11:10

seriyPS