summaryrefslogtreecommitdiff
path: root/docs/quick_tutorial/forms.rst
diff options
context:
space:
mode:
Diffstat (limited to 'docs/quick_tutorial/forms.rst')
-rw-r--r--docs/quick_tutorial/forms.rst146
1 files changed, 146 insertions, 0 deletions
diff --git a/docs/quick_tutorial/forms.rst b/docs/quick_tutorial/forms.rst
new file mode 100644
index 000000000..bb7cab3f7
--- /dev/null
+++ b/docs/quick_tutorial/forms.rst
@@ -0,0 +1,146 @@
+====================================
+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 and validation. This also gives us the
+:ref:`Colander <colander:overview>` for schemas and validation.
+
+Deform is getting a facelift, with styling from Twitter Bootstrap and
+advanced widgets from popular JavaScript projects. The work began in
+``deform_bootstrap`` and is being merged into an update to Deform.
+
+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
+
+ (env27)$ 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
+ :linenos:
+
+#. We can now install our project in development mode:
+
+ .. code-block:: bash
+
+ (env27)$ python setup.py develop
+
+#. Register a static view in ``forms/tutorial/__init__.py`` for
+ Deform's CSS/JS etc. as well as our demo wikipage scenario'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:
+
+#. Finally, a template at ``forms/tutorial/wikipage_view.pt``
+ for viewing a wiki page:
+
+ .. literalinclude:: forms/tutorial/wikipage_view.pt
+ :language: html
+ :linenos:
+
+#. Run your Pyramid application with:
+
+ .. code-block:: bash
+
+ (env27)$ 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 pages,
+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 JS just
+mentioned. Deform has a :term:`resource registry` which allows widgets
+to specify which JS 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
+whether you are walking up to it 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.