1 .. -*- coding: utf-8 -*- |
|
2 |
|
3 |
|
4 Tutoriel : créer votre première application web pour Postgres |
|
5 ============================================================= |
|
6 |
|
7 |
|
8 [TRANSLATE ME TO FRENCH] |
|
9 |
|
10 Ce tutoriel va vous guider pas à pas a construire une apllication web |
|
11 de gestion de Blog afin de vous faire découvrir les fonctionnalités de |
|
12 `CubicWeb`. |
|
13 |
|
14 Nous supposons que vous avec déjà suivi le guide :ref:`MiseEnPlaceEnv` |
|
15 |
|
16 |
|
17 This tutorial will guide you step by step to build a blog application |
|
18 and discover the unique features of `LAX`. It assumes that you followed |
|
19 the :ref:`installation` guidelines and that both the `AppEngine SDK` and the |
|
20 `LAX` framework are setup on your computer. |
|
21 |
|
22 Creating a new application |
|
23 -------------------------- |
|
24 |
|
25 We choosed in this tutorial to develop a blog as an example of web application |
|
26 and will go through each required steps/actions to have it running with `LAX`. |
|
27 When you installed `LAX`, you saw a directory named ``skel``. Make a copy of |
|
28 this directory and call it ``BlogDemo``. |
|
29 |
|
30 The location of this directory does not matter. But once decided, make sure your ``PYTHONPATH`` is properly set (:ref:`installation`). |
|
31 |
|
32 |
|
33 Defining a schema |
|
34 ----------------- |
|
35 |
|
36 With `LAX`, the schema/datamodel is the core of the application. This is where |
|
37 you will define the type of content you have to hanlde in your application. |
|
38 |
|
39 Let us start with something simple and improve on it iteratively. |
|
40 |
|
41 In schema.py, we define two entities : ``Blog`` and ``BlogEntry``. |
|
42 |
|
43 :: |
|
44 |
|
45 class Blog(EntityType): |
|
46 title = String(maxsize=50, required=True) |
|
47 description = String() |
|
48 |
|
49 class BlogEntry(EntityType): |
|
50 title = String(maxsize=100, required=True) |
|
51 publish_date = Date(default='TODAY') |
|
52 text = String(fulltextindexed=True) |
|
53 category = String(vocabulary=('important','business')) |
|
54 entry_of = SubjectRelation('Blog', cardinality='?*') |
|
55 |
|
56 A Blog has a title and a description. The title is a string that is |
|
57 required by the class EntityType and must be less than 50 characters. |
|
58 The description is a string that is not constrained. |
|
59 |
|
60 A BlogEntry has a title, a publish_date and a text. The title is a |
|
61 string that is required and must be less than 100 characters. The |
|
62 publish_date is a Date with a default value of TODAY, meaning that |
|
63 when a BlogEntry is created, its publish_date will be the current day |
|
64 unless it is modified. The text is a string that will be indexed in |
|
65 the full-text index and has no constraint. |
|
66 |
|
67 A BlogEntry also has a relationship ``entry_of`` that link it to a |
|
68 Blog. The cardinality ``?*`` means that a BlogEntry can be part of |
|
69 zero or one Blog (``?`` means `zero or one`) and that a Blog can |
|
70 have any number of BlogEntry (``*`` means `any number including |
|
71 zero`). For completeness, remember that ``+`` means `one or more`. |
|
72 |
|
73 Running the application |
|
74 ----------------------- |
|
75 |
|
76 Defining this simple schema is enough to get us started. Make sure you |
|
77 followed the setup steps described in detail in the installation |
|
78 chapter (especially visiting http://localhost:8080/_load as an |
|
79 administrator), then launch the application with the command:: |
|
80 |
|
81 python dev_appserver.py BlogDemo |
|
82 |
|
83 and point your browser at http://localhost:8080/ (if it is easier for |
|
84 you, use the on-line demo at http://lax.appspot.com/). |
|
85 |
|
86 .. image:: images/lax-book.00-login.fr.png |
|
87 :alt: login screen |
|
88 |
|
89 After you log in, you will see the home page of your application. It |
|
90 lists the entity types: Blog and BlogEntry. If these links read |
|
91 ``blog_plural`` and ``blogentry_plural`` it is because |
|
92 internationalization (i18n) is not working for you yet. Please ignore |
|
93 this for now. |
|
94 |
|
95 .. image:: images/lax-book.01-start.fr.png |
|
96 :alt: home page |
|
97 |
|
98 Creating system entities |
|
99 ------------------------ |
|
100 You can only create new users if you decided not to use google authentication. |
|
101 |
|
102 |
|
103 [WRITE ME : create users manages permissions etc] |
|
104 |
|
105 |
|
106 |
|
107 Creating application entites |
|
108 ---------------------------- |
|
109 |
|
110 Create a Blog |
|
111 ~~~~~~~~~~~~~ |
|
112 |
|
113 Let us create a few of these entities. Click on the [+] at the right |
|
114 of the link Blog. Call this new Blog ``Tech-blog`` and type in |
|
115 ``everything about technology`` as the description, then validate the |
|
116 form by clicking on ``Validate``. |
|
117 |
|
118 .. image:: images/lax-book.02-create-blog.fr.png |
|
119 :alt: from to create blog |
|
120 |
|
121 Click on the logo at top left to get back to the home page, then |
|
122 follow the Blog link that will list for you all the existing Blog. |
|
123 You should be seeing a list with a single item ``Tech-blog`` you |
|
124 just created. |
|
125 |
|
126 .. image:: images/lax-book.03-list-one-blog.fr.png |
|
127 :alt: displaying a list of a single blog |
|
128 |
|
129 Clicking on this item will get you to its detailed description except |
|
130 that in this case, there is not much to display besides the name and |
|
131 the phrase ``everything about technology``. |
|
132 |
|
133 .. image:: images/lax-book.04-detail-one-blog.fr.png |
|
134 :alt: displaying the detailed view of a blog |
|
135 |
|
136 Now get back to the home page by clicking on the top-left logo, then |
|
137 create a new Blog called ``MyLife`` and get back to the home page |
|
138 again to follow the Blog link for the second time. The list now |
|
139 has two items. |
|
140 |
|
141 .. image:: images/lax-book.05-list-two-blog.fr.png |
|
142 :alt: displaying a list of two blogs |
|
143 |
|
144 |
|
145 Create a BlogEntry |
|
146 ~~~~~~~~~~~~~~~~~~ |
|
147 |
|
148 Get back to the home page and click on [+] at the right of the link |
|
149 BlogEntry. Call this new entry ``Hello World`` and type in some text |
|
150 before clicking on ``Validate``. You added a new blog entry without |
|
151 saying to what blog it belongs. There is a box on the left entitled |
|
152 ``actions``, click on the menu item ``modify``. You are back to the form |
|
153 to edit the blog entry you just created, except that the form now has |
|
154 another section with a combobox titled ``add relation``. Chose |
|
155 ``entry_of`` in this menu and a second combobox appears where you pick |
|
156 ``MyLife``. |
|
157 |
|
158 You could also have, at the time you started to fill the form for a |
|
159 new entity BlogEntry, hit ``Apply`` instead of ``Validate`` and the |
|
160 combobox titled ``add relation`` would have showed up. |
|
161 |
|
162 .. image:: images/lax-book.06-add-relation-entryof.fr.png |
|
163 :alt: editing a blog entry to add a relation to a blog |
|
164 |
|
165 Validate the changes by clicking ``Validate``. The entity BlogEntry |
|
166 that is displayed now includes a link to the entity Blog named |
|
167 ``MyLife``. |
|
168 |
|
169 .. image:: images/lax-book.07-detail-one-blogentry.fr.png |
|
170 :alt: displaying the detailed view of a blogentry |
|
171 |
|
172 Remember that all of this was handled by the framework and that the |
|
173 only input that was provided so far is the schema. To get a graphical |
|
174 view of the schema, run the ``laxctl genschema BlogDemo`` command as |
|
175 explained in the installation section and point your browser to the |
|
176 URL http://localhost:8080/schema |
|
177 |
|
178 .. image:: images/lax-book.08-schema.fr.png |
|
179 :alt: graphical view of the schema (aka data-model) |
|
180 |
|
181 Site configuration |
|
182 ------------------ |
|
183 |
|
184 .. image:: images/lax-book.03-site-config-panel.fr.png |
|
185 |
|
186 This panel allows you to configure the appearance of your application site. |
|
187 Six menus are available and we will go through each of them to explain how |
|
188 to use them. |
|
189 |
|
190 Navigation |
|
191 ~~~~~~~~~~ |
|
192 This menu provides you a way to adjust some navigation options depending on |
|
193 your needs, such as the number of entities to display by page of results. |
|
194 Follows the detailled list of available options : |
|
195 |
|
196 * navigation.combobox-limit : maximum number of entities to display in related |
|
197 combo box (sample format: 23) |
|
198 * navigation.page-size : maximum number of objects displayed by page of results |
|
199 (sample format: 23) |
|
200 * navigation.related-limit : maximum number of related entities to display in |
|
201 the primary view (sample format: 23) |
|
202 * navigation.short-line-size : maximum number of characters in short description |
|
203 (sample format: 23) |
|
204 |
|
205 UI |
|
206 ~~ |
|
207 This menu provides you a way to customize the user interface settings such as |
|
208 date format or encoding in the produced html. |
|
209 Follows the detailled list of available options : |
|
210 |
|
211 * ui.date-format : how to format date in the ui ("man strftime" for format description) |
|
212 * ui.datetime-format : how to format date and time in the ui ("man strftime" for format |
|
213 description) |
|
214 * ui.default-text-format : default text format for rich text fields. |
|
215 * ui.encoding : user interface encoding |
|
216 * ui.fckeditor :should html fields being edited using fckeditor (a HTML WYSIWYG editor). |
|
217 You should also select text/html as default text format to actually get fckeditor. |
|
218 * ui.float-format : how to format float numbers in the ui |
|
219 * ui.language : language of the user interface |
|
220 * ui.main-template : id of main template used to render pages |
|
221 * ui.site-title : site title, which is displayed right next to the logo in the header |
|
222 * ui.time-format : how to format time in the ui ("man strftime" for format description) |
|
223 |
|
224 |
|
225 Actions |
|
226 ~~~~~~~ |
|
227 This menu provides a way to configure the context in which you expect the actions |
|
228 to be displayed to the user and if you want the action to be visible or not. |
|
229 You must have notice that when you view a list of entities, an action box is |
|
230 available on the left column which display some actions as well as a drop-down |
|
231 menu for more actions. |
|
232 |
|
233 The context available are : |
|
234 |
|
235 * mainactions : actions listed in the left box |
|
236 * moreactions : actions listed in the `more` menu of the left box |
|
237 * addrelated : add actions listed in the left box |
|
238 * useractions : actions listed in the first section of drop-down menu |
|
239 accessible from the right corner user login link |
|
240 * siteactions : actions listed in the second section of drop-down menu |
|
241 accessible from the right corner user login link |
|
242 * hidden : select this to hide the specific action |
|
243 |
|
244 Boxes |
|
245 ~~~~~ |
|
246 The application has already a pre-defined set of boxes you can use right away. |
|
247 This configuration section allows you to place those boxes where you want in the |
|
248 application interface to customize it. |
|
249 |
|
250 The available boxes are : |
|
251 |
|
252 * actions box : box listing the applicable actions on the displayed data |
|
253 |
|
254 * boxes_blog_archives_box : box listing the blog archives |
|
255 |
|
256 * possible views box : box listing the possible views for the displayed data |
|
257 |
|
258 * rss box : RSS icon to get displayed data as a RSS thread |
|
259 |
|
260 * search box : search box |
|
261 |
|
262 * startup views box : box listing the configuration options available for |
|
263 the application site, such as `Preferences` and `Site Configuration` |
|
264 |
|
265 Components |
|
266 ~~~~~~~~~~ |
|
267 [WRITE ME] |
|
268 |
|
269 Contextual components |
|
270 ~~~~~~~~~~~~~~~~~~~~~ |
|
271 [WRITE ME] |
|
272 |
|
273 Set-up a workflow |
|
274 ----------------- |
|
275 |
|
276 Before starting, make sure you refresh your mind by reading [link to |
|
277 definition_workflow chapter]. |
|
278 |
|
279 We want to create a workflow to control the quality of the BlogEntry |
|
280 submitted on your application. When a BlogEntry is created by a user |
|
281 its state should be `submitted`. To be visible to all, it needs to |
|
282 be in the state `published`. To move from `submitted` to `published` |
|
283 we need a transition that we can name `approve_blogentry`. |
|
284 |
|
285 We do not want every user to be allowed to change the state of a |
|
286 BlogEntry. We need to define a group of user, `moderators`, and |
|
287 this group will have appropriate permissions to approve BlogEntry |
|
288 to be published and visible to all. |
|
289 |
|
290 There are two ways to create a workflow, form the user interface, |
|
291 and also by defining it in ``migration/postcreate.py``. This script |
|
292 is executed each time a new ``./bin/laxctl db-init`` is done. |
|
293 If you create the states and transitions through the user interface |
|
294 this means that next time you will need to initialize the database |
|
295 you will have to re-create all the entities. |
|
296 We strongly recommand you create the workflow in ``migration\postcreate.py`` |
|
297 and we will now show you how. |
|
298 The user interface would only be a reference for you to view the states |
|
299 and transitions but is not the appropriate interface to define your |
|
300 application workflow. |
|
301 |
|
302 Update the schema |
|
303 ~~~~~~~~~~~~~~~~~ |
|
304 To enable a BlogEntry to have a State, we have to define a relation |
|
305 ``in_state`` in the schema of BlogEntry. Please do as follows, add |
|
306 the line ``in_state (...)``:: |
|
307 |
|
308 class BlogEntry(EntityType): |
|
309 title = String(maxsize=100, required=True) |
|
310 publish_date = Date(default='TODAY') |
|
311 text_format = String(meta=True, internationalizable=True, maxsize=50, |
|
312 default='text/rest', constraints=[format_constraint]) |
|
313 text = String(fulltextindexed=True) |
|
314 category = String(vocabulary=('important','business')) |
|
315 entry_of = SubjectRelation('Blog', cardinality='?*') |
|
316 in_state = SubjectRelation('State', cardinality='1*') |
|
317 |
|
318 As you updated the schema, you will have re-execute ``./bin/laxctl db-init`` |
|
319 to initialize the database and migrate your existing entities. |
|
320 [WRITE ABOUT MIGRATION] |
|
321 |
|
322 Create states, transitions and group permissions |
|
323 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
|
324 |
|
325 At the time the ``postcreate.py`` script is executed, several methods |
|
326 can be used. They are all defined in the ``class ServerMigrationHelper``. |
|
327 We will only discuss the method we use to create a wrokflow here. |
|
328 |
|
329 To define our workflow for BlogDemo, please add the following lines |
|
330 to ``migration/postcreate.py``:: |
|
331 |
|
332 _ = unicode |
|
333 |
|
334 moderators = add_entity('CWGroup', name=u"moderators") |
|
335 |
|
336 submitted = add_state(_('submitted'), 'BlogEntry', initial=True) |
|
337 published = add_state(_('published'), 'BlogEntry') |
|
338 |
|
339 add_transition(_('approve_blogentry'), 'BlogEntry', (submitted,), published, ('moderators', 'managers'),) |
|
340 |
|
341 checkpoint() |
|
342 |
|
343 ``add_entity`` is used here to define the new group of users that we |
|
344 need to define the transitions, `moderators`. |
|
345 If this group required by the transition is not defined before the |
|
346 transition is created, it will not create the relation `transition |
|
347 require the group moderator`. |
|
348 |
|
349 ``add_state`` expects as the first argument the name of the state you are |
|
350 willing to create, then the entity type on which the state can be applied, |
|
351 and an optionnal argument to set if the state is the initial state |
|
352 of the entity type or not. |
|
353 |
|
354 ``add_transition`` expects as the first argument the name of the |
|
355 transition, then the entity type on which we can apply the transition, |
|
356 then the list of possible initial states from which the transition |
|
357 can be applied, the target state of the transition, and the permissions |
|
358 (e.g. list of the groups of users who can apply the transition). |
|
359 |
|
360 .. image:: images/lax-book.03-transitions-view.fr.png |
|
361 |
|
362 You can now notice that in the actions box of a BlogEntry, the state |
|
363 is now listed as well as the possible transitions from this state |
|
364 defined by the workflow. This transition, as defined in the workflow, |
|
365 will only being displayed for the users belonging to the group |
|
366 moderators of managers. |
|
367 |
|
368 Change view permission |
|
369 ~~~~~~~~~~~~~~~~~~~~~~ |
|
370 |
|
371 |
|
372 |
|
373 Conclusion |
|
374 ---------- |
|
375 |
|
376 Exercise |
|
377 ~~~~~~~~ |
|
378 |
|
379 Create new blog entries in ``Tech-blog``. |
|
380 |
|
381 What we learned |
|
382 ~~~~~~~~~~~~~~~ |
|
383 |
|
384 Creating a simple schema was enough to set up a new application that |
|
385 can store blogs and blog entries. |
|
386 |
|
387 What is next ? |
|
388 ~~~~~~~~~~~~~~ |
|
389 |
|
390 Although the application is fully functionnal, its look is very |
|
391 basic. In the following section we will learn to create views to |
|
392 customize how data is displayed. |
|
393 |
|
394 |
|