I recall reading somewhere that the distinction between a framework and a library was that in a library, you[r code] calls the functions it needs, whilst in a framework, it calls you.
Often, bugs in your code will manifest as the framework throwing exceptions somewhere internally, often with difficult to interpret stack traces until you're familiar with how things work and what parts are safe to ignore.
I've not had much success with interactive debugging in django (recommendations/howtos would be hugely appreciated), but I can imagine a similar situation in which you have to learn what is safe to skip through (and maybe how to automate that to break only at points of interest, especially those points which are in some internal django setup methods)
Most of my most time consuming django hours involve forms or admin. it's not that there is a bug in my code, it's just very twisted and thick in there.
Eg. Form classes are created dynamically per request and then instantiated. Lots of currying, many places that params can be specified.
Yep, forms (and presently, Tastypie) are the biggest hassle for me as well. Digging through the internals of CBVs in order to figure out annoying little mixin-related quirks probably comes second.
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 :)).
What are you using? They are pretty convenient with WTForms.
# 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.
I disagree. I found WTForms quite easy to use and straight forward. I believe there's even a Flask-WTForms module. It's very natural. I was just thinking the other day how nice forms are in Flask. Having to write ky own forms stuff in Scala.
Not necessarily a bug, more often it's just something not working the way you expect. Documentation is always ambiguous when you get down to the fine details and even in a very well documented project like Django there is still a whole lot of code surface area that is not documented other than an autogenerated API listing.