.. _qtut_forms:
|
|
====================================
|
18: Forms and Validation with Deform
|
====================================
|
|
Schema-driven, autogenerated forms with validation.
|
|
|
Background
|
==========
|
|
Modern web applications deal extensively with forms. Developers, though, have a
|
wide range of philosophies about how frameworks should help them with their
|
forms. As such, Pyramid doesn't directly bundle one particular form library.
|
Instead there are a variety of form libraries that are easy to use in Pyramid.
|
|
:ref:`Deform <deform:overview>` is one such library. In this step, we introduce
|
Deform for our forms. This also gives us :ref:`Colander <colander:overview>`
|
for schemas and validation.
|
|
|
Objectives
|
==========
|
|
- Make a schema using Colander, the companion to Deform.
|
|
- Create a form with Deform and change our views to handle validation.
|
|
|
Steps
|
=====
|
|
#. First we copy the results of the ``view_classes`` step:
|
|
.. code-block:: bash
|
|
$ cd ..; cp -r view_classes forms; cd forms
|
|
#. Let's edit ``forms/setup.py`` to declare a dependency on Deform (which then
|
pulls in Colander as a dependency:
|
|
.. literalinclude:: forms/setup.py
|
:emphasize-lines: 4
|
:linenos:
|
|
#. We can now install our project in development mode:
|
|
.. code-block:: bash
|
|
$ $VENV/bin/pip install -e .
|
|
#. Register a static view in ``forms/tutorial/__init__.py`` for Deform's CSS,
|
JavaScript, etc., as well as our demo wiki page's views:
|
|
.. literalinclude:: forms/tutorial/__init__.py
|
:linenos:
|
|
#. Implement the new views, as well as the form schemas and some dummy data, in
|
``forms/tutorial/views.py``:
|
|
.. literalinclude:: forms/tutorial/views.py
|
:linenos:
|
|
#. A template for the top of the "wiki" in ``forms/tutorial/wiki_view.pt``:
|
|
.. literalinclude:: forms/tutorial/wiki_view.pt
|
:language: html
|
:linenos:
|
|
#. Another template for adding/editing in
|
``forms/tutorial/wikipage_addedit.pt``:
|
|
.. literalinclude:: forms/tutorial/wikipage_addedit.pt
|
:language: html
|
:linenos:
|
|
#. Add a template at ``forms/tutorial/wikipage_view.pt`` for viewing a wiki
|
page:
|
|
.. literalinclude:: forms/tutorial/wikipage_view.pt
|
:language: html
|
:linenos:
|
|
#. Our tests in ``forms/tutorial/tests.py`` don't run, so let's modify them:
|
|
.. literalinclude:: forms/tutorial/tests.py
|
:linenos:
|
|
#. Run the tests:
|
|
.. code-block:: bash
|
|
$ $VENV/bin/py.test tutorial/tests.py -q
|
..
|
2 passed in 0.45 seconds
|
|
#. Run your Pyramid application with:
|
|
.. code-block:: bash
|
|
$ $VENV/bin/pserve development.ini --reload
|
|
#. Open http://localhost:6543/ in a browser.
|
|
|
Analysis
|
========
|
|
This step helps illustrate the utility of asset specifications for static
|
assets. We have an outside package called Deform with static assets which need
|
to be published. We don't have to know where on disk it is located. We point at
|
the package, then the path inside the package.
|
|
We just need to include a call to ``add_static_view`` to make that directory
|
available at a URL. For Pyramid-specific packages, Pyramid provides a facility
|
(``config.include()``) which even makes that unnecessary for consumers of a
|
package. (Deform is not specific to Pyramid.)
|
|
Our forms have rich widgets which need the static CSS and JavaScript just
|
mentioned. Deform has a :term:`resource registry` which allows widgets to
|
specify which JavaScript and CSS are needed. Our ``wikipage_addedit.pt``
|
template shows how we iterated over that data to generate markup that includes
|
the needed resources.
|
|
Our add and edit views use a pattern called *self-posting forms*. Meaning, the
|
same URL is used to ``GET`` the form as is used to ``POST`` the form. The
|
route, the view, and the template are the same URL whether you are walking up
|
to it for the first time or you clicked a button.
|
|
Inside the view we do ``if 'submit' in self.request.params:`` to see if this
|
form was a ``POST`` where the user clicked on a particular button
|
``<input name="submit">``.
|
|
The form controller then follows a typical pattern:
|
|
- If you are doing a ``GET``, skip over and just return the form.
|
|
- If you are doing a ``POST``, validate the form contents.
|
|
- If the form is invalid, bail out by re-rendering the form with the supplied
|
``POST`` data.
|
|
- If the validation succeeded, perform some action and issue a redirect via
|
``HTTPFound``.
|
|
We are, in essence, writing our own form controller. Other Pyramid-based
|
systems, including ``pyramid_deform``, provide a form-centric view class which
|
automates much of this branching and routing.
|
|
|
Extra credit
|
============
|
|
#. Give a try at a button that goes to a delete view for a particular wiki
|
page.
|