Eg. Form classes are created dynamically per request and then instantiated. Lots of currying, many places that params can be specified.
Eg. Form classes are created dynamically per request and then instantiated. Lots of currying, many places that params can be specified.
Even in spite of all that, it's still the nicest (and by far the most well-documented) framework I've used.
If I had to pick one complaint, I'd say the "define fields as class-variables" for forms and models is a bit too magical, and picking through the metaclass implementation to understand exactly what things happen when can be a pain, and I'm not 100% sold that 'reduced boilerplate' is a good enough reason for it (there may be other good reasons. I'm just whining :)).
# models.py
class Post(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(80))
title = db.Column(db.String(200))
content = db.Column(db.Text)
def __init__(self, name, title, content):
self.name = name
self.title = title
self.content = content
# forms.py
import flaskext.wtf as wtf
from flaskext.wtf import Form, validators
from wtforms.ext.sqlalchemy.orm import model_form
import models
PostForm = model_form(models.Post, Form, field_args = {
'name': {'validators': [validators.required()]},
'title': {'validators': [validators.required(), validators.length(min=5)]},
})
# views.py
def post_new():
form = forms.PostForm()
if form.validate_on_submit():
post = models.Post(form.name.data, form.title.data, form.content.data)
db.session.add(post)
db.session.commit()
return redirect(url_for('post.index'))
return render_template('post/new.slim', form=form)
# _post_form.slim
- from 'helpers.slim' import render_field
form method="POST" class="well"
= form.hidden_tag()
= render_field(form.name, class\="span4")
= render_field(form.title, class\="span4")
= render_field(form.content, class\="span4")
.field
input type="submit" class="btn btn-success"
# post/new.slim
- extends 'layout.slim'
- block content
.span6
h2 Creating new post
- include 'post/_post_form.slim'
a href="=url_for('.index')" class="btn btn-primary btn-small" Back
# helpers.slim
- macro render_field(field)
div class="{{ 'field-with-errors' if field.errors else 'field' }}"
- if field.errors
- for error in field.errors
p class="error" = error
= field.label
= (field(**kwargs) | safe)
Don't bother about the slim templates. It's a small jinja2 extension which I use to give me slim syntax.Now this probably looks like a lot. But consider that you write the helper to render the form only once. Also, you can write a helper to generate models and form scaffolding for you. That's what I do.
python manage.py create_model post -f 'name:String(80) title:String(200) content:Text'
It generates me the model, form and form template(models.py, forms.py, _post_form.py). The form of course will have empty validators which I fill.Edit: stupid auto-correct.