Added WTForms documentation.
This commit is contained in:
parent
73a47a0db1
commit
ce18d4575d
6 changed files with 115 additions and 10 deletions
|
|
@ -242,5 +242,6 @@ latex_documents = [
|
||||||
intersphinx_mapping = {
|
intersphinx_mapping = {
|
||||||
'http://docs.python.org/dev': None,
|
'http://docs.python.org/dev': None,
|
||||||
'http://werkzeug.pocoo.org/documentation/dev/': None,
|
'http://werkzeug.pocoo.org/documentation/dev/': None,
|
||||||
'http://www.sqlalchemy.org/docs/': None
|
'http://www.sqlalchemy.org/docs/': None,
|
||||||
|
'http://wtforms.simplecodes.com/docs/0.5/': None
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -96,14 +96,6 @@ This is possible as well, but I would not recommend it. Just run
|
||||||
|
|
||||||
(Run it in an Admin shell on Windows systems and without the `sudo`).
|
(Run it in an Admin shell on Windows systems and without the `sudo`).
|
||||||
|
|
||||||
|
|
||||||
The Drop into Place Version
|
|
||||||
---------------------------
|
|
||||||
|
|
||||||
Now I really don't recommend this way on using Flask, but you can do that
|
|
||||||
of course as well. Download the `dip` zipfile from the website and unzip
|
|
||||||
it next to your application.
|
|
||||||
|
|
||||||
.. _windows-easy-install:
|
.. _windows-easy-install:
|
||||||
|
|
||||||
`easy_install` on Windows
|
`easy_install` on Windows
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
.. _message-flashing-pattern:
|
||||||
|
|
||||||
Message Flashing
|
Message Flashing
|
||||||
================
|
================
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -16,5 +16,6 @@ end of the request, the database connection is closed again.
|
||||||
packages
|
packages
|
||||||
sqlite3
|
sqlite3
|
||||||
sqlalchemy
|
sqlalchemy
|
||||||
|
wtforms
|
||||||
templateinheritance
|
templateinheritance
|
||||||
flashing
|
flashing
|
||||||
|
|
|
||||||
109
docs/patterns/wtforms.rst
Normal file
109
docs/patterns/wtforms.rst
Normal file
|
|
@ -0,0 +1,109 @@
|
||||||
|
Form Validation with WTForms
|
||||||
|
============================
|
||||||
|
|
||||||
|
When you have to work with form data submitted by a browser view code
|
||||||
|
quickly becomes very hard to read. There are libraries out there designed
|
||||||
|
to make this process easier to manage. One of them is WTForms which we
|
||||||
|
will handle here. If you find yourself in the situation of having many
|
||||||
|
forms, you might want to give it a try.
|
||||||
|
|
||||||
|
When you are working with WTForms you have to define your forms as classes
|
||||||
|
first. I recommend breaking up the application into multiple modules
|
||||||
|
(:ref:`larger-applications`) for that and adding a separate module for the
|
||||||
|
forms.
|
||||||
|
|
||||||
|
The Forms
|
||||||
|
---------
|
||||||
|
|
||||||
|
This is an example form for a typical registration page::
|
||||||
|
|
||||||
|
from wtforms import Form, BooleanField, TextField, validators
|
||||||
|
|
||||||
|
class RegistrationForm(Form):
|
||||||
|
username = TextField('Username', [validators.Length(min=4, max=25)])
|
||||||
|
email = TextField('Email Address', [validators.Length(min=6, max=35)])
|
||||||
|
password = PasswordField('New Password', [Required(),
|
||||||
|
EqualTo('confirm', mesage='Passwords must match')])
|
||||||
|
confirm = PasswordField('Repeat Password')
|
||||||
|
accept_tos = BooleanField('I accept the TOS', [validators.Required()])
|
||||||
|
|
||||||
|
In the View
|
||||||
|
-----------
|
||||||
|
|
||||||
|
In the view function, the usage of this form looks like this::
|
||||||
|
|
||||||
|
@app.route('/register', methods=['GET', 'POST'])
|
||||||
|
def register():
|
||||||
|
form = RegistrationForm(request.form)
|
||||||
|
if request.method == 'POST' and form.validate():
|
||||||
|
user = User(form.username.data, form.email.data,
|
||||||
|
form.password.data)
|
||||||
|
db_session.add(user)
|
||||||
|
flash('Thanks for registering')
|
||||||
|
redirect(url_for('login'))
|
||||||
|
return render_template('register.html', form=form)
|
||||||
|
|
||||||
|
Notice that we are implying that the view is using SQLAlchemy here
|
||||||
|
(:ref:`sqlalchemy-pattern`) but this is no requirement of course. Adapt
|
||||||
|
the code as necessary.
|
||||||
|
|
||||||
|
Things to remember:
|
||||||
|
|
||||||
|
1. create the form from the request :attr:`~flask.request.form` value if
|
||||||
|
the data is submitted via the HTTP `POST` method and
|
||||||
|
:attr:`~flask.request.args` if the data is submitted as `GET`.
|
||||||
|
2. to validate the data, call the :func:`~wtforms.form.Form.validate`
|
||||||
|
method which will return `True` if the data validates, `False`
|
||||||
|
otherwise.
|
||||||
|
3. to access individual values from the form, access `form.<NAME>.data`.
|
||||||
|
|
||||||
|
Forms in Templates
|
||||||
|
------------------
|
||||||
|
|
||||||
|
Now to the template side. When you pass the form to the templates you can
|
||||||
|
easily render them there. Look at the following example template to see
|
||||||
|
how easy this is. WTForms does half the form generation for us already.
|
||||||
|
To make it even nicer, we can write a macro that renders a field with
|
||||||
|
label and a list of errors if there are any.
|
||||||
|
|
||||||
|
Here an example `_formhelpers.html` template with such a macro:
|
||||||
|
|
||||||
|
.. sourcecode:: html+jinja
|
||||||
|
|
||||||
|
{% 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 %}
|
||||||
|
|
||||||
|
This macro accepts a couple of keyword arguments that are forwarded to
|
||||||
|
WTForm's field function that renders the field for us. They keyword
|
||||||
|
arguments will be inserted as HTML attributes. So for example you can
|
||||||
|
call ``render_field(form.username, class='username')`` to add a class to
|
||||||
|
the input element. Note that WTForms returns standard Python unicode
|
||||||
|
strings, so we have to tell Jinja2 that this data is already HTML escaped
|
||||||
|
with the `|safe` filter.
|
||||||
|
|
||||||
|
Here the `register.html` template for the function we used above which
|
||||||
|
takes advantage of the `_formhelpers.html` template:
|
||||||
|
|
||||||
|
.. sourcecode:: html+jinja
|
||||||
|
|
||||||
|
{% from "_formhelpers.html" import render_field %}
|
||||||
|
<form method="POST" action="/register">
|
||||||
|
<dl>
|
||||||
|
{{ render_field(form.username) }}
|
||||||
|
{{ render_field(form.email) }}
|
||||||
|
{{ render_field(form.password) }}
|
||||||
|
{{ render_field(form.confirm) }}
|
||||||
|
{{ render_field(form.accept_tos) }}
|
||||||
|
</dl>
|
||||||
|
<p><input type=submit value=Register>
|
||||||
|
</form>
|
||||||
|
|
@ -368,7 +368,7 @@ u'Marked up \xbb HTML'
|
||||||
|
|
||||||
.. [#] Unsure what that :class:`~flask.g` object is? It's something you
|
.. [#] Unsure what that :class:`~flask.g` object is? It's something you
|
||||||
can store information on yourself, check the documentation of that
|
can store information on yourself, check the documentation of that
|
||||||
object (:class:`~flask.g`) and the :ref:`database-pattern` for more
|
object (:class:`~flask.g`) and the :ref:`sqlite3` for more
|
||||||
information.
|
information.
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue