[IMP] models: move prefetching of records back to method _prefetch_field
[odoo/odoo.git] / doc / howto / howto_website.rst
1 ===================================
2 Howto: build a website with OpenERP
3 ===================================
4
5 .. queue:: howto_website/series
6
7 .. warning::
8
9    This guide assumes `basic knowledge of python
10    <http://docs.python.org/2/tutorial/>`_.
11
12    This guide assumes :ref:`an OpenERP installed and ready for development
13    <getting_started_installation_source-link>`.
14
15    For production deployment, see the dedicated guides :ref:`using-gunicorn`
16    and :ref:`using-mod-wsgi`.
17
18 Creating a basic module
19 =======================
20
21 In OpenERP, doing things takes the form of creating modules, and these modules
22 customize the behavior of the OpenERP installation. The first step is thus to
23 create a module: at the command-line, go to your server's directory and enter
24
25 .. code-block:: console
26
27     $ ./oe scaffold Academy ../my-modules
28
29 This will build a basic module for you in a directory called ``my-modules``
30 right next to your server's directory:
31
32 .. code-block:: text
33
34     academy
35     ├── __init__.py
36     ├── __openerp__.py
37     ├── controllers
38     │   ├── __init__.py
39     │   └── academy.py
40     ├── models
41     │   ├── __init__.py
42     │   └── academy.py
43     └── security
44         └── ir.model.access.csv
45
46 * ``academy`` is the root directory of your module
47 * ``__init__.py`` tells Python that it is a valid package, and imports
48   sub-packages and sub-modules
49 * ``__openerp__.py`` provides various meta-information about your module to
50   OpenERP (a short description, the module's dependencies, its author, its
51   version, ...)
52 * ``controllers`` holds the object responding to web (browser) requests
53   - ``academy.py`` is where a default controller has been created for you
54 * ``models`` holds OpenERP stored objects, ignore it for now, we'll dive into
55   it when `storing data in OpenERP`
56 * ``ir.model.access.csv`` defines basic access rights to the models, you can
57   also ignore it for now
58
59 .. patch::
60     :hidden:
61
62 Now we can create a database, start your OpenERP server and install your new
63 module in it:
64
65 .. code-block:: console
66
67     $ createdb academy
68     $ ./openerp-server --addons-path=addons,../my-modules \
69                        -d academy -i academy --db-filter=academy
70
71 * ``--addons-path`` tells OpenERP where it can find its modules. By default it
72   will only look into ``openerp/addons``, this adds the web client modules,
73   the "standard" business modules (not needed yet) and the place where your
74   own ``academy`` module lives.
75 * ``-i`` installs the provided module name in the database specified via
76   ``-d``
77 * ``--db-filter`` means the specified database will be selected by default in
78   the web interface, and will be the only one selectable (makes starting
79   things up simpler)
80
81 Once the installation is finished you should see ``HTTP service (werkzeug)
82 running on 0.0.0.0:8069`` and nothing more happening in the log. You can now
83 open a web browser and navigate to http://localhost:8069. A page should
84 appear with just the words "Hello, world!" on it:
85
86 .. image:: howto_website/helloworld.png
87
88 This page is generated by the ``index`` method in
89 :file:`academy/controllers/academy.py`, which just returns some text. Let's
90 make it prettier by returning HTML and using bootstrap_ to get a nicer default
91 rendering:
92
93 .. patch::
94
95 Restart the server, refresh the page
96
97 .. image:: howto_website/hellobootstrap.png
98
99 Although it is subtle for so little text and markup, the font has changed and
100 margins have been added to the page.
101
102 .. note::
103
104    this example requires internet access as we're accessing a :abbr:`CDN
105    (Content Delivery Network, large distributed networks hosting static files
106    and trying to provide high-performance and high-availability of these
107    files)`-hosted file.
108
109 .. note::
110
111     At this point, the OpenERP server has no autoreloader. Every time you
112     Python code (and later templates or data files), you should restart the
113     server using the original startup instruction (without the re-creation of
114     the database)
115
116 Controller Parameters
117 =====================
118
119 For dynamic pages, query parameters are passed as string parameters to the
120 controller method. For instance the index page can display a list of teaching
121 assistants, and link to each assistant's page using an index (in a global
122 array for now):
123
124 .. patch::
125
126 No validation is performed on query input values, it could be missing
127 altogether (if a user accesses ``/tas/`` directly) or it could be incorrectly
128 formatted. For this reason, query parameters are generally used to provide
129 "options" to a given page, and "required" data tends (when possible) to be
130 inserted directly in the URL.
131
132 This we can do by adding `converter patterns`_ to the URL in ``@http.route``:
133
134 .. patch::
135
136 These patterns will generally do some validation (e.g. if the ``id`` is not
137 a valid integer the converter will result in a ``404 Not Found`` page instead
138 of a 500 server error when the conversion failed in our own code) and may
139 perform some parsing or type conversion (in this case the conversion from a
140 URL section — a string — to a Python integer).
141
142 Basic templates
143 ===============
144
145 So far we've output HTML by munging strings. It works, but is not exactly fun
146 to edit (and somewhat unsafe to boot) as even advanced text editors have a
147 hard time understanding they're dealing with HTML embedded in Python code.
148
149 The usual solution is to use templates_, documents with placeholders which can
150 be "rendered" to produce final pages (or others). OpenERP lets you use any
151 Python templating system you want, but bundles its own :doc:`QWeb
152 </06_ir_qweb>` templating system which we'll later see offers some useful
153 features.
154
155 Let's move our 2 pseudo-templates from inline strings to actual templates:
156
157 .. patch::
158
159 This simplifies the controller code by moving data formatting out of it, and
160 generally makes it simpler for designers to edit the markup.
161
162 .. note::
163
164     You'll need to update the module to install the new templates
165
166 .. todo:: link to section about reusing/altering existing stuff, template
167           overriding
168
169 .. _howto-website-support:
170
171 OpenERP's Website support
172 =========================
173
174 OpenERP 8 is bundled with new modules dedicated specifically to building
175 websites (whether it be simply sets of pages or more complex components such
176 as blogs).
177
178 First, we'll install the ``website`` module: restart your server with
179
180 .. code-block:: console
181
182     $ ./openerp-server --addons-path=addons,../my-modules \
183                        -d academy -i website --db-filter=academy
184
185 If you navigate to `your openerp`_, your basic page may have been replaced by
186 the generic index page of the ``website`` module. Don't panic! (if it has not
187 been replaced, don't panic either). The problem here is that both ``website``
188 and ``academy`` try to handle the ``/`` (root) URL, and which one *gets* it
189 depends on the order in which they're loaded (the last loaded module gets the
190 last say), which itself depends on a bunch of irrelevant stuff and is
191 essentially non-deterministic at this point.
192
193 To make loading order deterministic, we can add ``website`` as a dependency
194 to ``academy``:
195
196 .. patch::
197
198 This tells OpenERP that ``academy`` needs ``website`` to work correctly, and
199 that it must only be loaded after ``website`` has already been loaded. This
200 ensures ``academy``'s index page overwrites ``website``'s.
201
202 .. note::
203
204     because a change in dependencies is a metadata alteration, you'll need
205     to force an update to your module: restart your server with
206
207     .. code-block:: console
208
209         $ ./openerp-server --addons-path=addons,../my-modules \
210                            -d academy -u academy --db-filter=academy
211
212     instead of the previous command (note: ``-i`` was replaced by ``-u``)
213
214 If you reload `your openerp`_, you can see that your old index page hasn't
215 changed at all. Which is odd since we wanted to use the new ``website``
216 tools.
217
218 That is because much of these tools are inserted and enabled by the "layout
219 template" provided by ``website``.  Let's use that layout instead of our own
220 page structure:
221
222 .. patch::
223
224 * ``website.layout`` is the main Website layout, it provides standard headers
225   and footers as well as integration with various customization tools.
226
227 * there's quite a bit of complex markup, used as hooks for various features
228   (e.g. snippets). Although technically not mandatory, some things will not
229   work if they're not there.
230
231 Reload `your openerp`_, the page has changed and new content has appeared
232 (footer, menus, …) but there's still no advanced edition tools in sight, as
233 you are not yet logged-in. Click on the :guilabel:`Sign In` link, fill in your
234 credentials (``admin``/``admin`` by default), click :guilabel:`Log in`.
235
236 You're now in OpenERP "proper", the backend/administrative interface. We'll
237 deal with it in :ref:`a latter section <howto-website-administration>`. For
238 now, click on the :menuselection:`Website` menu item in the top-left of the
239 browser, between :menuselection:`Messaging` and :menuselection:`Settings`.
240
241 You're back to your website, but are now an administrator and thus have access
242 to the advanced edition features of an OpenERP-built website.
243
244 * if you go in the HTML editor (:menuselection:`Customize --> HTML Editor`),
245   you can see and edit your template
246 * if you click the :menuselection:`Edit` button in the top left, you'll switch
247   to "Edition Mode" where the blocks (snippets) and rich text edition are
248   available.
249 * there are a number of other features in the advanced editor, which we will
250   not cover here
251
252   .. todo:: link to document walking through editor features
253
254 .. todo:: website template generator
255
256 You can play around and add blocks or edit content on the home page, however
257 if you go to a TA's page and edit it things seem to work at first (e.g. insert
258 a :guilabel:`image-text` snippet to one of the TAs, as if adding a picture
259 and a short bio), but if you go to a different TA's page after saving the
260 first one… he has the exact same snippet inserted (and the same content, if
261 you edited the snippet's content)!
262
263 Because snippets are added in the template itself, they're content which is
264 the same across all pages using that template, and all the teaching assistants
265 share the same template (``academy.ta``).
266
267 Thus snippets are mostly for generic content, when a given template is only
268 used for a single page, or to add content in HTML fields.
269
270 .. todo:: link HTML fields to HTML fields doc?
271
272 .. note::
273
274     When creating a new page (e.g. via :menuselection:`Content --> New Page`),
275     OpenERP will duplicate a "source" template, and create a new template for
276     each page. As a result, it's safe to use dedicated-content snippets for
277     "static" pages.
278
279 Storing data in OpenERP
280 =======================
281
282 The conceptual storage model of OpenERP is simple: there are storage tables,
283 represented by OpenERP models, and inside these tables are records. The first
284 step, then, is to define a model.
285
286 We'll start by moving our teaching assistants in the database:
287
288 .. patch::
289
290 We've also altered the index method slightly, to retrieve our teaching
291 assistants from the database instead of storing them in a global list in the
292 module\ [#taprofile]_.
293
294 .. note:: :file:`ir.model.access.csv` is necessary to tell OpenERP that any
295           user can *see* the teaching assistants: by default, only the
296           administrator can see, edit, create or destroy objects.  Here, we
297           only change the ``read`` permission to allow any user to list and
298           browse teaching assistants.
299
300 .. todo:: command/shortcut
301
302 Update the module, reload `your openerp`_… and the Teaching Assistants list is
303 empty since we haven't put any TA in the database.
304
305 Let's add them in data files:
306
307 .. patch::
308
309 Update the module again, reload `your openerp`_ and the TAs are back.
310
311 .. warning:: if you can't see your data, check that you have reloaded the
312              server with ``-i academy``, not ``-u academy``, new data files
313              are not installed with ``-u``.
314
315 Click on a TA name, and you'll see an error message. Let's fix the TA view
316 now:
317
318 .. patch::
319
320 There are a few non-obvious things here, so let's go through them for clarity:
321
322 * OpenERP provides a has a special `converter pattern`_, which knows how to
323   retrieve OpenERP objects by identifier. Instead of an integer or other
324   similar basic value, ``ta`` thus gets a full-blown ``academy.tas`` object,
325   without having to retrieve it by hand (as is done in ``index``).
326
327 * However because the ``model()`` `converter pattern`_ takes an identifier, we
328   have to alter the creation of ``ta``'s URL to include such an identifier,
329   rather than an index in an array
330
331 * Finally, ``website.render()`` wants a dict as its rendering context, not an
332   object, which is why we wrap our ``ta`` object into one.
333
334 We're still where we started this section though: if we add snippets to or
335 edit the text of a TA's page, these editions will be visible across all TA
336 pages since they'll be stored in the shared ``academy.ta`` template.
337
338 Not only that, but we can not even edit the TA's name, even though it's not
339 shared content.
340
341 Let's fix that first, instead of using the basic "display this content"
342 template tag ``t-esc``, we'll use one aware of OpenERP objects and their
343 fields:
344
345 .. patch::
346
347 Update the module, go into a TA page and activate the edition mode. If you
348 move your mouse over the TA's name, it is surrounded by a yellow border, and
349 you can edit its content. If you change the name of a TA and save the page,
350 the change is correctly stored in the TA's record, the name is fixed when you
351 go to the index page but other TAs remain unaffected.
352
353 For the issue of customizing our TA profiles, we can expand our model with a
354 "freeform" HTML field:
355
356 .. patch::
357
358 Then, insert the new biographical content in the template using the same
359 object-aware template tag:
360
361 .. patch::
362
363 Update the module, browse to a TA's page and open the edition mode (using the
364 :guilabel:`Edit` button in the window's top-right).  The empty HTML field now
365 displays a big placeholder image, if you drop snippets in or write some
366 content for one of the teaching assistants, you will see that other TA
367 profiles are unaffected.
368
369 A more complex model
370 --------------------
371
372 Up to now, we've been working with displaying and manipulating objects
373 representing teaching assistants. It's a basic and simple concept, but not one
374 which allows for much further diving into interesting tools of OpenERP.
375
376 We need an object fitting the theme yet allowing for richer interactions and
377 more interesting extensions. Course lectures seem to fit: they can be
378 displayed in various manners (e.g. as a list of lectures or as a calendar),
379 they can be moved around as necessary (cancelled/rescheduled), they can have
380 numerous pieces of data attached both intrinsic (lecture transcripts) and
381 extrinsic (attendance records, student discussions, etc…).
382
383 .. patch::
384
385 Note a new feature: ``t-field`` tags can take options through
386 ``t-field-options``. The options must be a JSON_ object. Available options
387 depend on the field's type and potentially the display widget (some types
388 of fields can be displayed in multiple manners). In this case, the same
389 ``date`` field is displayed using custom date formats, one being the generic
390 ``long`` (which depends on the current user's locale) and the other being
391 an explicit format for `the weekday in short form
392 <http://babel.pocoo.org/docs/dates/#date-fields>`_.
393
394 .. note:: in edition mode, formatted date and datetime fields revert to a
395           canonical representation in order to provide all of the field's
396           information.
397
398 .. warning::
399
400     if you edit the course's dates, you will notice that the two displays of
401     the ``date`` field are not synchronized, if one is edited the second one
402     will not change until the edition is saved. This is a limitation of the
403     current ``website`` but may be improved in future releases.
404
405 .. sending & storing comments (?)
406
407 .. _howto-website-administration:
408
409 Administration and ERP Integration
410 ==================================
411
412 In practice, the data we've created so far using XML data files is usually
413 stored as "demo data", used for testing and demonstrations of modules, and the
414 actual user data is input via the OpenERP "backend", which we're going to try
415 out now. First let's move our data set to demo data:
416
417 .. patch::
418
419 the difference is simply that new databases can be created either in "demo"
420 mode or in "no demo" mode. In the former case, the database will be preloaded
421 with any demo data configured in the installed module.
422
423 A brief and incomplete introduction to the OpenERP administration
424 -----------------------------------------------------------------
425
426 You've already seen it for a very short time in :ref:`howto-website-support`,
427 you can go back to it using :menuselection:`Administrator --> Administration`
428 if you're already logged-in (which you should be), or go through
429 :menuselection:`Sign In` again if you are not.
430
431 The conceptual structure of the OpenERP backend is simple:
432
433 1. first are menus, menus are a tree (they can have sub-menus). To menus
434    without children is mapped…
435
436 2. an action. Actions have various types, they can be links, reports (PDF),
437    code which the server should execute or window actions. Window actions
438    tell the client to display the OpenERP object according to certain views…
439
440 3. a view has a type, the broad category to which it corresponds (tree, form,
441    graph, calendar, …) and its architecture which represents the way the
442    object is laid out inside the view.
443
444 By default, when an OpenERP object is *defined* it is essentially invisible in
445 the interface. To make it visible, it needs to be available through an action,
446 which itself needs to be reachable somehow, usually a through a menu.
447
448 Let us, then, create a menu and an action for our lectures:
449
450 .. patch::
451
452 .. note::
453
454     if a requested view does not exist, OpenERP will automatically generate a
455     very basic one on-the-fly. That is the case here as we have not yet
456     created a list and a form view for the lectures.
457
458 If you reload the backend, you should see a new menu :menuselection:`Academy`
459 at the top-left corner, before :menuselection:`Messaging`. In it is the
460 submenus we defined via ``menuitem``, and within (the first submenu is
461 selected by default) opens a list view of the lectures. To the right is a
462 series of 2 buttons, which lets you toggle between the "list" view (overview
463 of all records in the object) and the "form" view (view an manipulation of a
464 single record). The :guilabel:`Create` button above the list lets you create
465 new record, you can select records to delete them.
466
467 The names of the fields in the search and list view are automatically inferred
468 from the logical field names, but it's probably a good idea to specify them
469 anyway, by adding a ``string`` to the model field:
470
471 .. patch::
472
473 An issue is that the list view only displays the ``name`` field. To fix this,
474 we have to create an explicit list view for lectures:
475
476 .. patch::
477
478 .. todo:: link to list view documentation
479
480 Reusing and customizing existing work
481 -------------------------------------
482
483 OpenERP and its standard modules provide a number of models which may already
484 solve your problem or part of your problem. Part of being a good OpenERP
485 developer is having an idea of existing models and how they can be retrofit
486 to your purposes.
487
488 For our courses, instead of developing teaching assistants and lectures from
489 scratch we could reuse existing OpenERP *users* (for teaching assistants) and
490 *events* (for lectures)\ [#bonus]_, as well as the built-in website support
491 for events.
492
493 Install ``website_event`` (which will also install ``events``) by restarting
494 the server as:
495
496 .. code-block:: console
497
498     $ ./openerp-server --addons-path=addons,../my-modules \
499                        -d academy -i website_event --db-filter=academy
500
501 We'll also add it as a dependency to our module:
502
503 .. patch::
504
505 Reload `your openerp`_, click on the new :menuselection:`Events` item which
506 was added to the menu. This will be our new lectures page, but there are a few
507 adaptations to perform
508
509 Fixing the menu
510 ~~~~~~~~~~~~~~~
511
512 The menu title is currently a generic *Events*, we only want lectures so we
513 will rename it to *Lectures*. Website menu items are defined through the
514 ``website.menu`` model, *Events* is defined by ``website_event`` and has the
515 external id ``website_event.menu_events``, renaming it is as simple as
516 overwriting the ``name`` field for that record:
517
518 .. patch::
519
520 Restart the server with
521
522 .. code-block:: console
523
524     $ ./openerp-server --addons-path=addons,../my-modules \
525                        -d academy -i academy --db-filter=academy
526
527 and the menu item has been renamed to Lectures.
528
529 Removing the sidebar
530 ~~~~~~~~~~~~~~~~~~~~
531
532 The filters sidebar is not necessary for our lectures. It can be removed in
533 the UI via :menuselection:`Customize --> Filters` (and new filters can be
534 added to the current filtering by date). Template customization is done by
535 adding and removing extension views, so much like the renaming of the menu,
536 we simply need to find the right record (here the Filters template view
537 extending the basic event page) and set its value correctly:
538
539 .. todo:: documentation for view inheritance/in-place extension
540
541 .. patch::
542
543 Note that the option is still available in :menuselection:`Customize`, we
544 have merely flipped the default around.
545
546 Simplifying templates
547 ~~~~~~~~~~~~~~~~~~~~~
548
549 There are still two things to fix in the lectures list. First, remove the
550 *Our Events* link in the top-left corner, simply replace the breadcrumb
551 element by nothing:
552
553 .. patch::
554
555 Second, remove the "organized by" and type rows in the event's description,
556 keep only the datetime and location:
557
558 .. patch::
559
560 Moving lectures and TAs
561 ~~~~~~~~~~~~~~~~~~~~~~~
562
563 The gist of the operation is fairly simple, but there are lots of changes:
564
565 * The custom models can be removed as we'll be using standard objects
566 * The controller has to be altered to fetch from standard objects
567   (``event.event`` and ``res.users``), we'll use groups to discriminate
568   between our academy objects and other demo objects, so that has to be used
569   as well
570 * HTML templates have to be slightly edited to match the new objects
571   (our lecture's ``date`` field is replaced by ``event.event``'s
572   ``date_begin``)
573 * Missing parts of the standard events have to be added (``res.partner``,
574   which is where "personal" informations are stored for ``res.users``, does
575   not have a biographical field. We have to add it)
576 * Finally demo files must be converted, and existing demo data should be
577   purged if we do not need it (e.g. existing non-lectures events and event
578   types can be removed before adding our own)
579
580 .. note::
581
582     because we're reusing the old XIDs on completely different models, we need
583     to either remove the old reference or (simpler) just drop and re-create
584     the database
585
586 .. patch::
587
588 Our data is back in the fontend (site), and in the backend we get
589 administrative views for free, e.g. a calendar view of our lectures.
590
591 .. [#taprofile] the teaching assistants profile view ends up broken for now,
592                 but don't worry we'll get around to it
593
594 .. [#bonus] as a bonus, we get access rights and TA access to the
595             administrative backend "for free"
596
597 .. _bootstrap: http://getbootstrap.com
598
599 .. _converter pattern:
600 .. _converter patterns:
601     http://werkzeug.pocoo.org/docs/routing/#rule-format
602
603 .. _templates: http://en.wikipedia.org/wiki/Web_template
604
605 .. _your openerp: http://localhost:8069/
606
607 .. _JSON: http://www.json.org