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 |
|
42aa12
|
34 |
#. First we copy the results of the ``view_classes`` step: |
b1b922
|
35 |
|
42aa12
|
36 |
.. code-block:: bash |
b1b922
|
37 |
|
42aa12
|
38 |
cd ..; cp -r view_classes forms; cd forms |
b1b922
|
39 |
|
42aa12
|
40 |
#. Let's edit ``forms/setup.py`` to declare a dependency on Deform, which in turn pulls in Colander as a dependency: |
b1b922
|
41 |
|
42aa12
|
42 |
.. literalinclude:: forms/setup.py |
e73977
|
43 |
:emphasize-lines: 6 |
42aa12
|
44 |
:linenos: |
b1b922
|
45 |
|
42aa12
|
46 |
#. We can now install our project in development mode: |
b1b922
|
47 |
|
42aa12
|
48 |
.. code-block:: bash |
b1b922
|
49 |
|
42aa12
|
50 |
$VENV/bin/pip install -e . |
b1b922
|
51 |
|
42aa12
|
52 |
#. Register a static view in ``forms/tutorial/__init__.py`` for Deform's CSS, JavaScript, etc., as well as our demo wiki page's views: |
b1b922
|
53 |
|
42aa12
|
54 |
.. literalinclude:: forms/tutorial/__init__.py |
SP |
55 |
:linenos: |
b1b922
|
56 |
|
42aa12
|
57 |
#. Implement the new views, as well as the form schemas and some dummy data, in ``forms/tutorial/views.py``: |
b1b922
|
58 |
|
42aa12
|
59 |
.. literalinclude:: forms/tutorial/views.py |
SP |
60 |
:linenos: |
b1b922
|
61 |
|
42aa12
|
62 |
#. A template for the top of the "wiki" in ``forms/tutorial/wiki_view.pt``: |
b1b922
|
63 |
|
42aa12
|
64 |
.. literalinclude:: forms/tutorial/wiki_view.pt |
SP |
65 |
:language: html |
|
66 |
:linenos: |
b1b922
|
67 |
|
42aa12
|
68 |
#. Another template for adding/editing in ``forms/tutorial/wikipage_addedit.pt``: |
b1b922
|
69 |
|
42aa12
|
70 |
.. literalinclude:: forms/tutorial/wikipage_addedit.pt |
SP |
71 |
:language: html |
|
72 |
:linenos: |
b1b922
|
73 |
|
42aa12
|
74 |
#. Add a template at ``forms/tutorial/wikipage_view.pt`` for viewing a wiki page: |
b1b922
|
75 |
|
42aa12
|
76 |
.. literalinclude:: forms/tutorial/wikipage_view.pt |
SP |
77 |
:language: html |
|
78 |
:linenos: |
59c8fc
|
79 |
|
42aa12
|
80 |
#. Our tests in ``forms/tutorial/tests.py`` don't run, so let's modify them: |
0d37a9
|
81 |
|
42aa12
|
82 |
.. literalinclude:: forms/tutorial/tests.py |
SP |
83 |
:linenos: |
0d37a9
|
84 |
|
42aa12
|
85 |
#. Run the tests: |
59c8fc
|
86 |
|
42aa12
|
87 |
.. code-block:: bash |
59c8fc
|
88 |
|
42aa12
|
89 |
$VENV/bin/pytest tutorial/tests.py -q |
SP |
90 |
.. |
|
91 |
6 passed in 0.81 seconds |
b1b922
|
92 |
|
42aa12
|
93 |
#. Run your Pyramid application with: |
b1b922
|
94 |
|
42aa12
|
95 |
.. code-block:: bash |
b1b922
|
96 |
|
42aa12
|
97 |
$VENV/bin/pserve development.ini --reload |
b1b922
|
98 |
|
42aa12
|
99 |
#. Open http://localhost:6543/ in a browser. |
b1b922
|
100 |
|
PE |
101 |
|
|
102 |
Analysis |
|
103 |
======== |
|
104 |
|
59c8fc
|
105 |
This step helps illustrate the utility of asset specifications for static |
SP |
106 |
assets. We have an outside package called Deform with static assets which need |
|
107 |
to be published. We don't have to know where on disk it is located. We point at |
|
108 |
the package, then the path inside the package. |
b1b922
|
109 |
|
59c8fc
|
110 |
We just need to include a call to ``add_static_view`` to make that directory |
SP |
111 |
available at a URL. For Pyramid-specific packages, Pyramid provides a facility |
|
112 |
(``config.include()``) which even makes that unnecessary for consumers of a |
|
113 |
package. (Deform is not specific to Pyramid.) |
b1b922
|
114 |
|
59c8fc
|
115 |
Our forms have rich widgets which need the static CSS and JavaScript just |
SP |
116 |
mentioned. Deform has a :term:`resource registry` which allows widgets to |
|
117 |
specify which JavaScript and CSS are needed. Our ``wikipage_addedit.pt`` |
|
118 |
template shows how we iterated over that data to generate markup that includes |
|
119 |
the needed resources. |
b1b922
|
120 |
|
59c8fc
|
121 |
Our add and edit views use a pattern called *self-posting forms*. Meaning, the |
SP |
122 |
same URL is used to ``GET`` the form as is used to ``POST`` the form. The |
|
123 |
route, the view, and the template are the same URL whether you are walking up |
|
124 |
to it for the first time or you clicked a button. |
b1b922
|
125 |
|
59c8fc
|
126 |
Inside the view we do ``if 'submit' in self.request.params:`` to see if this |
SP |
127 |
form was a ``POST`` where the user clicked on a particular button |
b1b922
|
128 |
``<input name="submit">``. |
PE |
129 |
|
|
130 |
The form controller then follows a typical pattern: |
|
131 |
|
59c8fc
|
132 |
- If you are doing a ``GET``, skip over and just return the form. |
b1b922
|
133 |
|
59c8fc
|
134 |
- If you are doing a ``POST``, validate the form contents. |
b1b922
|
135 |
|
59c8fc
|
136 |
- If the form is invalid, bail out by re-rendering the form with the supplied |
SP |
137 |
``POST`` data. |
b1b922
|
138 |
|
59c8fc
|
139 |
- If the validation succeeded, perform some action and issue a redirect via |
SP |
140 |
``HTTPFound``. |
b1b922
|
141 |
|
59c8fc
|
142 |
We are, in essence, writing our own form controller. Other Pyramid-based |
SP |
143 |
systems, including ``pyramid_deform``, provide a form-centric view class which |
|
144 |
automates much of this branching and routing. |
b1b922
|
145 |
|
59c8fc
|
146 |
|
SP |
147 |
Extra credit |
b1b922
|
148 |
============ |
PE |
149 |
|
59c8fc
|
150 |
#. Give a try at a button that goes to a delete view for a particular wiki |
SP |
151 |
page. |