Steve Piercy
2018-05-19 92396fec03f546a708f79ef39838709a9ad44ea5
commit | author | age
b731b5 1 .. _qtut_forms:
PE 2
b1b922 3 ====================================
ab0319 4 18: Forms and Validation with Deform
b1b922 5 ====================================
PE 6
7 Schema-driven, autogenerated forms with validation.
8
59c8fc 9
b1b922 10 Background
PE 11 ==========
12
59c8fc 13 Modern web applications deal extensively with forms. Developers, though, have a
SP 14 wide range of philosophies about how frameworks should help them with their
15 forms. As such, Pyramid doesn't directly bundle one particular form library.
16 Instead there are a variety of form libraries that are easy to use in Pyramid.
b1b922 17
59c8fc 18 :ref:`Deform <deform:overview>` is one such library. In this step, we introduce
SP 19 Deform for our forms. This also gives us :ref:`Colander <colander:overview>`
003b9a 20 for schemas and validation.
59c8fc 21
b1b922 22
PE 23 Objectives
24 ==========
25
59c8fc 26 - Make a schema using Colander, the companion to Deform.
b1b922 27
59c8fc 28 - Create a form with Deform and change our views to handle validation.
SP 29
b1b922 30
PE 31 Steps
32 =====
33
34 #. First we copy the results of the ``view_classes`` step:
35
36    .. code-block:: bash
37
187104 38     $ cd ..; cp -r view_classes forms; cd forms
b1b922 39
59c8fc 40 #. Let's edit ``forms/setup.py`` to declare a dependency on Deform (which then
SP 41    pulls in Colander as a dependency:
b1b922 42
PE 43    .. literalinclude:: forms/setup.py
263ba4 44     :emphasize-lines: 4
b1b922 45     :linenos:
PE 46
47 #. We can now install our project in development mode:
48
49    .. code-block:: bash
50
9845f7 51       $ $VENV/bin/pip install -e .
b1b922 52
59c8fc 53 #. Register a static view in ``forms/tutorial/__init__.py`` for Deform's CSS,
SP 54    JavaScript, etc., as well as our demo wiki page's views:
b1b922 55
PE 56    .. literalinclude:: forms/tutorial/__init__.py
57     :linenos:
58
59c8fc 59 #. Implement the new views, as well as the form schemas and some dummy data, in
SP 60    ``forms/tutorial/views.py``:
b1b922 61
PE 62    .. literalinclude:: forms/tutorial/views.py
63     :linenos:
64
59c8fc 65 #. A template for the top of the "wiki" in ``forms/tutorial/wiki_view.pt``:
b1b922 66
PE 67    .. literalinclude:: forms/tutorial/wiki_view.pt
68     :language: html
69     :linenos:
70
71 #. Another template for adding/editing in
72    ``forms/tutorial/wikipage_addedit.pt``:
73
74    .. literalinclude:: forms/tutorial/wikipage_addedit.pt
75     :language: html
76     :linenos:
77
0d37a9 78 #. Add a template at ``forms/tutorial/wikipage_view.pt`` for viewing a wiki
SP 79    page:
b1b922 80
PE 81    .. literalinclude:: forms/tutorial/wikipage_view.pt
82     :language: html
83     :linenos:
59c8fc 84
0d37a9 85 #. Our tests in ``forms/tutorial/tests.py`` don't run, so let's modify them:
SP 86
87    .. literalinclude:: forms/tutorial/tests.py
88     :linenos:
89
59c8fc 90 #. Run the tests:
SP 91
92    .. code-block:: bash
93
94     $ $VENV/bin/py.test tutorial/tests.py -q
95     ..
96     2 passed in 0.45 seconds
b1b922 97
PE 98 #. Run your Pyramid application with:
99
100    .. code-block:: bash
101
187104 102     $ $VENV/bin/pserve development.ini --reload
b1b922 103
d749bf 104 #. Open http://localhost:6543/ in a browser.
b1b922 105
PE 106
107 Analysis
108 ========
109
59c8fc 110 This step helps illustrate the utility of asset specifications for static
SP 111 assets. We have an outside package called Deform with static assets which need
112 to be published. We don't have to know where on disk it is located. We point at
113 the package, then the path inside the package.
b1b922 114
59c8fc 115 We just need to include a call to ``add_static_view`` to make that directory
SP 116 available at a URL. For Pyramid-specific packages, Pyramid provides a facility
117 (``config.include()``) which even makes that unnecessary for consumers of a
118 package. (Deform is not specific to Pyramid.)
b1b922 119
59c8fc 120 Our forms have rich widgets which need the static CSS and JavaScript just
SP 121 mentioned. Deform has a :term:`resource registry` which allows widgets to
122 specify which JavaScript and CSS are needed. Our ``wikipage_addedit.pt``
123 template shows how we iterated over that data to generate markup that includes
124 the needed resources.
b1b922 125
59c8fc 126 Our add and edit views use a pattern called *self-posting forms*. Meaning, the
SP 127 same URL is used to ``GET`` the form as is used to ``POST`` the form. The
128 route, the view, and the template are the same URL whether you are walking up
129 to it for the first time or you clicked a button.
b1b922 130
59c8fc 131 Inside the view we do ``if 'submit' in self.request.params:`` to see if this
SP 132 form was a ``POST`` where the user clicked on a particular button
b1b922 133 ``<input name="submit">``.
PE 134
135 The form controller then follows a typical pattern:
136
59c8fc 137 - If you are doing a ``GET``, skip over and just return the form.
b1b922 138
59c8fc 139 - If you are doing a ``POST``, validate the form contents.
b1b922 140
59c8fc 141 - If the form is invalid, bail out by re-rendering the form with the supplied
SP 142   ``POST`` data.
b1b922 143
59c8fc 144 - If the validation succeeded, perform some action and issue a redirect via
SP 145   ``HTTPFound``.
b1b922 146
59c8fc 147 We are, in essence, writing our own form controller. Other Pyramid-based
SP 148 systems, including ``pyramid_deform``, provide a form-centric view class which
149 automates much of this branching and routing.
b1b922 150
59c8fc 151
SP 152 Extra credit
b1b922 153 ============
PE 154
59c8fc 155 #. Give a try at a button that goes to a delete view for a particular wiki
SP 156    page.