There are some helpful extensions for many popular model mappings (SQLAlchemy, App Engine, and Django) bundled with WTForms that allow you to easily create a wtforms.form.Form from a model.
If using the Flask-WTForms extension, however, you'll want to make sure you pass the base_class as flaskext.wtf.Form from the Flask extension so the created form includes all the API improvements from the extension (ex. form.validate_on_submit()).
from flaskext.wtf import Form
from wtforms.ext.appengine.db import model_form
from models import MyModel
MyForm = model_form(MyModel, Form)
Note: In this example I am using App Engine's models and thus using model_form() from wtforms.ext.appengine.db. If using SQLAlchemy, you will want to use model_form() from wtforms.ext.sqlalchemy.orm. This is currently not documented on WTForms extensions page, but you can see it's been available since 0.5 (source | changelog).
You will want to refer the WTForms extension docs for more details, but one nice item to mention is you can customize the created form at creation. Here is an example of adding an extra validator to one of the fields
from flaskext.wtf import Form
from wtforms.ext.appengine.db import model_form
from wtforms import validators
from models import MyModel
MyForm = model_form(MyModel, Form, field_args = {
'name' : {
'validators' : [validators.Length(max=10)]
}
})
Note: model_form() will add validators automatically to the created Form based on your model definitions, such as if a field is required.
Here is a full example using a created form.
from flaskext.wtf import Form
from wtforms.ext.appengine.db import model_form
from models import MyModel
@app.route("/edit<id>")
def edit(id):
MyForm = model_form(MyModel, Form)
model = MyModel.get(id)
form = MyForm(request.form, model)
if form.validate_on_submit():
form.populate_obj(model)
model.put()
flash("MyModel updated")
return redirect(url_for("index"))
return render_template("edit.html", form=form)
This snippet by Sean Lynch can be used freely for anything you like. Consider it public domain.
Comments
Can't run snippet by Maxim Krivodaev on 2012-05-15 @ 06:43
Hello. I try use this snippet with: flask 0.8, sqlalchemy 0.7.7 and wtf 1.1. When I try go to edit page, I have error: AttributeError: type object 'User' has no attribute 'properties'. Could you describe how check it?
Excuse me by Maxim Krivodaev on 2012-05-15 @ 07:20
Attentively read the text
Comment by Sean Lynch on 2012-06-14 @ 14:59
Sorry, just now seeing this (I don't receive email notifications on comments). The example was using appengine, and properties() is a class method on the base Model. Since you are using SqlAlchemy, were you sure to use `from wtforms.ext.sqlalchemy.orm import model_form` and not `from wtforms.ext.appengine.db import model_form`? Just a guess without seeing the code.
Typo on first line of usage example by Matt Carrier on 2013-02-27 @ 06:32
Hi I'm not sure if this is like a wiki anyone can edit? I think there is a typo on the first line of the example snippet.
from flaskext.wtf import Form
Should be:
from flask.ext.wtf import Form
Out of Date? by Adrian Mouat on 2013-04-19 @ 14:17
This snippet confused me for a while.
Either it's out of date or I'm using slightly different libraries.
In particular I had to change:
if form.validate_on_submit():
to
if request.method == 'POST' and form.validate():
and I had to remove the model.put() line (I replaced it with db.session.commit(), but I guess this might not be required in some set-ups).
Ooops by Adrian Mouat on 2013-04-19 @ 14:38
It still seems slightly out-of-date, but the reason for validate_on_submit not being available was that the flask.ext.wtf version of Form wasn't be passed properly. Try changing:
MyForm = model_form(MyModel, Form)
To:
MyForm = model_form(MyModel, base_class=Form)
I think this was caused by arguments changing order between versions of wtforms.ext.sqlalchemy.orm.