rendering forms with flask + wtform

19,339

Solution 1

You're passing a form class not a form instance to the template. The model_form method generates a new class dynamically, which can be re-used, extended, and otherwise used like any other form subclass. It's also quite un-necessary to generate this form class on every run of your view, so you can move this call outside of your view.

You passing an uninstantiated class is also why you get strange behavior relating to UnboundField (which is how WTForms handles declarative field instantiation)

The fix is simple:

MemberForm = model_form(Member, base_class=Form)

@simple_page.route('/register')
def register():
    form = MemberForm(name=u'bad')
    return render_template('register.html', form=form)

Solution 2

You need to do a bit more work:

{{ form.name.label }} : {{ form.name()|safe }}

Or, you can use this handy snippet:

{% macro render_field(field) %}
  <dt>{{ field.label }}
  <dd>{{ field(**kwargs)|safe }}
  {% if field.errors %}
    <ul class=errors>
    {% for error in field.errors %}
      <li>{{ error }}</li>
    {% endfor %}
    </ul>
  {% endif %}
  </dd>
{% endmacro %}

Of course, adjust the HTML rendered. Save that file somewhere in your templates directory and then in your main template. Here its formhelpers.html:

{% from "formhelpers.html" import render_field %}
<form method=post action="/register">
  <dl>
    {{ render_field(form.name) }}
    {{ render_field(form.email) }}
  </dl>
  <p><input type=submit value=Register>
</form>

Solution 3

I know this is pretty old, but I had the same problem and I want to share my solution for futures needs.

I also got the html rendered by "UnboundField". After fighting with the code I found out i'm using:

from wtforms import Form

And it's looks good, but when using Flask I had to do this:

from flask.ext.wtf import Form

Fixed my problem. Hope it's helped

Share:
19,339
tipu
Author by

tipu

code n stuff

Updated on June 23, 2022

Comments

  • tipu
    tipu almost 2 years

    code in question:

    from flask import Blueprint, render_template, abort
    from flask.ext.wtf import Form
    import os
    from jinja2 import TemplateNotFound
    from models import Member
    from wtforms.ext.sqlalchemy.orm import model_form
    @simple_page.route('/register')
    def register():
        form = model_form(Member, Form)
        return render_template('register.html', form=form, name="bad")
    
    
    class Member(db.Model):
        id = db.Column(db.Integer, primary_key=True)
        name = db.Column(db.String(50), nullable=False)
        email = db.Column(db.String(50), nullable=False, unique=True)
    

    and in my view:

            <p class="txt11 colorb">
            {{ form.name }}
            </p>
    

    this outputs <UnboundField(TextField, (), {u'default': None, u'filters': [], u'validators': [<wtforms.validators.Required object at 0x7f62f59b5590>, <wtforms.validators.Length object at 0x7f62f59b55d0>]})>, not an actual field. how do i get an actual form/field with the wtform?

  • tipu
    tipu about 11 years
    i tried your suggestion, i get: TypeError: 'Unbound Field' object is not callable.