[IMP] doc/howtos/backend: usage of odoo.py
[odoo/odoo.git] / doc / howtos / backend.rst
1 .. queue:: backend/series
2
3 =======
4 Backend
5 =======
6
7 Start/Stop the Odoo server
8 ==========================
9
10 Odoo uses a client/server architecture in which clients are web browsers
11 accessing the odoo server via RPC.
12
13 Business logic and extension is generally performed on the server side,
14 although supporting client features (e.g. new data representation such as
15 interactive maps) can be added to the client.
16
17 In order to start the server, simply invoke the command :ref:`odoo.py
18 <reference/cmdline>` in the shell, adding the full path to the file if
19 necessary:
20
21 .. code:: bash
22
23     odoo.py
24
25 The server is stopped by hitting ``Ctrl-C`` twice from the terminal, or by
26 killing the corresponding OS process.
27
28 Build an Odoo module
29 ====================
30
31 Both server and client extensions are packaged as *modules* which are
32 optionally loaded in a *database*.
33
34 Odoo modules can either add brand new business logic to an Odoo system, or
35 alter and extend existing business logic: a module can be created to add your
36 country's accounting rules to Odoo's generic accounting support, while the
37 next module adds support for real-time visualisation of a bus fleet.
38
39 Everything in Odoo thus starts and ends with modules.
40
41 Composition of a module
42 -----------------------
43
44 An Odoo module can contain a number of elements:
45
46 Business objects
47     declared as Python classes, these resources are automatically persisted
48     by Odoo based on their configuration
49
50 Data files
51     XML or CSV files declaring metadata (views or workflows), configuration
52     data (modules parameterization), demonstration data and more
53
54 Web controllers
55     Handle requests from web browsers
56
57 Static web data
58     Images, CSS or javascript files used by the web interface or website
59
60 Module structure
61 ----------------
62
63 Each module is a directory within a *module directory*. Module directories
64 are specified by using the :option:`--addons-path <odoo.py --addons-path>`
65 option.
66
67 .. tip::
68     :class: aphorism
69
70     most command-line options can also be set using :ref:`a configuration
71     file <reference/cmdline/config>`
72
73 An Odoo module is declared by its :ref:`manifest <reference/module/manifest>`. It
74 is mandatory and contains a single python dictionary declaring various
75 metadata for the module: the module's name and description, list of Odoo
76 modules required for this one to work properly, references to data files, …
77
78 The manifest's general structure is::
79
80     {
81         'name': "MyModule",
82         'version': '1.0',
83         'depends': ['base'],
84         'author': "Author Name",
85         'category': 'Category',
86         'description': """
87         Description text
88         """,
89         # data files always loaded at installation
90         'data': [
91             'mymodule_view.xml',
92         ],
93         # data files containing optionally loaded demonstration data
94         'demo': [
95             'demo_data.xml',
96         ],
97     }
98
99 A module is also a
100 `Python package <http://docs.python.org/2/tutorial/modules.html#packages>`_
101 with a ``__init__.py`` file, containing import instructions for various Python
102 files in the module.
103
104 For instance, if the module has a single ``mymodule.py`` file ``__init__.py``
105 might contain::
106
107     import mymodule
108
109 Fortunately, there is a mechanism to help you set up an module. The command
110 ``odoo.py`` has a subcommand :ref:`scaffold <reference/cmdline/scaffold>` to
111 create an empty module:
112
113 .. code:: bash
114
115     odoo.py scaffold <module name> <where to put it>
116
117 The command creates a subdirectory for your module, and automatically creates a
118 bunch of standard files for a module. Most of them simply contain commented code
119 or XML. The usage of most of those files will be explained along this tutorial.
120
121 .. exercise:: Module creation
122
123     Use the command line above to  create an empty module Open Academy, and
124     install it in Odoo.
125
126     .. only:: solutions
127
128         #. Invoke the command ``odoo.py scaffold openacademy addons``.
129         #. Adapt the manifest file to your module.
130         #. Don't bother about the other files.
131
132         .. patch::
133
134 Object-Relational Mapping
135 -------------------------
136
137 A key component of Odoo is the :abbr:`ORM (Object-Relational Mapping)` layer.
138 This layer avoids having to write most :abbr:`SQL (Structured Query Language)`
139 by hand and provides extensibility and security services\ [#rawsql]_.
140
141 Business objects are declared as Python classes extending
142 :class:`~openerp.models.Model` which integrates them into the automated
143 persistence system.
144
145 Models can be configured by setting a number of attributes at their
146 definition. The most important attribute is
147 :attr:`~openerp.models.Model._name` which is required and defines the name for
148 the model in the Odoo system. Here is a minimally complete definition of a
149 model::
150
151     from openerp import models
152     class MinimalModel(models.Model):
153         _name = 'test.model'
154
155 Model fields
156 ------------
157
158 Fields are used to define what the model can store and where. Fields are
159 defined as attributes on the model class::
160
161     from openerp import models, fields
162
163     class LessMinimalModel(models.Model):
164         _name = 'test.model2'
165
166         name = fields.Char()
167
168 Common Attributes
169 #################
170
171 Much like the model itself, its fields can be configured, by passing
172 configuration attributes as parameters::
173
174     name = field.Char(required=True)
175
176 Some attributes are available on all fields, here are the most common ones:
177
178 :attr:`~openerp.fields.Field.string` (``unicode``, default: field's name)
179     The label of the field in UI (visible by users).
180 :attr:`~openerp.fields.Field.required` (``bool``, default: ``False``)
181     If ``True``, the field can not be empty, it must either have a default
182     value or always be given a value when creating a record.
183 :attr:`~openerp.fields.Field.help` (``unicode``, default: ``''``)
184     Long-formm, provides a help tooltip to users in the UI.
185 :attr:`~openerp.fields.Field.index` (``bool``, default: ``False``)
186     Requests that Odoo create a `database index`_ on the column
187
188 Simple fields
189 #############
190
191 There are two broad categories of fields: "simple" fields which are atomic
192 values stored directly in the model's table and "relational" fields linking
193 records (of the same model or of different models).
194
195 Example of simple fields are :class:`~openerp.fields.Boolean`,
196 :class:`~openerp.fields.Date`, :class:`~openerp.fields.Char`.
197
198 Reserved fields
199 ###############
200
201 Odoo creates a few fields in all models\ [#autofields]_. These fields are
202 managed by the system and shouldn't be written to. They can be read if
203 useful or necessary:
204
205 :attr:`~openerp.fields.Model.id` (:class:`~openerp.fields.Id`)
206     the unique identifier for a record in its model
207 :attr:`~openerp.fields.Model.create_date` (:class:`~openerp.fields.Datetime`)
208     creation date of the record
209 :attr:`~openerp.fields.Model.create_uid` (:class:`~openerp.fields.Many2one`)
210     user who created the record
211 :attr:`~openerp.fields.Model.write_date` (:class:`~openerp.fields.Datetime`)
212     last modification date of the record
213 :attr:`~openerp.fields.Model.write_uid` (:class:`~openerp.fields.Many2one`)
214     user who last modified the record
215
216 Special fields
217 ##############
218
219 By default, Odoo also requires a ``name`` field on all models for various
220 display and search behaviors. The field used for these purposes can be
221 overridden by setting :attr:`~openerp.models.Model._rec_name`.
222
223 .. exercise:: Define a model
224
225     Define a new data model *Course* in the *openacademy* module. A course
226     has a title and a description. Courses must have a title.
227
228     .. only:: solutions
229
230         Edit the file ``openacademy/models.py`` to include a *Course* class.
231
232         .. patch::
233
234 Data files
235 ----------
236
237 Odoo is a highly data driven system. Although behavior is customized using
238 Python_ code part of a module's value is in the data it sets up when loaded.
239
240 .. tip:: some modules exist solely to add data into Odoo
241     :class: aphorism
242
243 Module data is declared via :ref:`data files <reference/data>`, XML files with
244 ``<record>`` elements. Each ``<record>`` element creates or updates a database
245 record.
246
247 .. code-block:: xml
248
249     <openerp>
250         <data>
251             <record model="{model name}" id="{record identifier}">
252                 <field name="{a field name}">{a value}</field>
253             </record>
254         </data>
255     <openerp>
256
257 * ``model`` is the name of the Odoo model for the record
258 * ``id`` is an :term:`external identifier`, it allows referring to the record
259   (without having to know its in-database identifier)
260 * ``<field>`` elements have a ``name`` which is the name of the field in the
261   model (e.g. ``description``). Their body is the field's value.
262
263 Data files have to be declared in the manifest file to be loaded, they can
264 be declared in the ``'data'`` list (always loaded) or in the ``'demo'`` list
265 (only loaded in demonstration mode).
266
267 .. exercise:: Define demonstration data
268
269     Create demonstration data filling the *Courses* model with a few
270     demonstration courses.
271
272     .. only:: solutions
273
274         Edit the file ``openacademy/demo.xml`` to include some data.
275
276         .. patch::
277
278 Actions and Menus
279 -----------------
280
281 Actions and menus are regular records in database, usually declared through
282 data files. Actions can be triggered in three ways:
283
284 #. by clicking on menu items (linked to specific actions)
285 #. by clicking on buttons in views (if these are connected to actions)
286 #. as contextual actions on object
287
288 Because menus are somewhat complex to declare there is a ``<menuitem>``
289 shortcut to declare an ``ir.ui.menu`` and connect it to the corresponding
290 action more easily.
291
292 .. code-block:: xml
293
294     <record model="ir.actions.act_window" id="action_list_ideas">
295         <field name="name">Ideas</field>
296         <field name="res_model">idea.idea</field>
297         <field name="view_mode">tree,form</field>
298     </record>
299     <menuitem id="menu_ideas" parent="menu_root" name="Ideas" sequence="10"
300               action="action_list_ideas"/>
301
302 .. danger::
303     :class: aphorism
304
305     The action must be declared before its corresponding menu in the XML file.
306
307     Data files are executed sequentially, the action's ``id`` must be present
308     in the database before the menu can be created.
309
310 .. exercise:: Define new menu entries
311
312     Define new menu entries to access courses and sessions under the
313     OpenAcademy menu entry. A user should be able to
314
315     - display a list of all the courses
316     - create/modify courses
317
318     .. only:: solutions
319
320         #. Create ``openacademy/views/openacademy.xml`` with an action and
321            the menus triggering the action
322         #. Add it to the ``data`` list of ``openacademy/__openerp__.py``
323
324         .. patch::
325
326 Basic views
327 ===========
328
329 Views define the way the records of a model are displayed. Each type of view
330 represents a mode of visualization (a list of records, a graph of their
331 aggregation, …). Views can either be requested generically via their type
332 (e.g. *a list of partners*) or specifically via their id. For generic
333 requests, the view with the correct type and the lowest priority will be
334 used (so the lowest-priority view of each type is the default view for that
335 type).
336
337 :ref:`View inheritance <reference/views/inheritance>` allows altering views
338 declared elsewhere (adding or removing content).
339
340 Generic view declaration
341 ------------------------
342
343 A view is declared as a record of the model ``ir.ui.view``. The view type
344 is implied by the root element of the ``arch`` field:
345
346 .. code-block:: xml
347
348     <record model="ir.ui.view" id="view_id">
349         <field name="name">view.name</field>
350         <field name="model">object_name</field>
351         <field name="priority" eval="16"/>
352         <field name="arch" type="xml">
353             <!-- view content: <form>, <tree>, <graph>, ... -->
354         </field>
355     </record>
356
357 .. danger:: The view's content is XML.
358     :class: aphorism
359
360     The ``arch`` field must thus be declared as ``type="xml"`` to be parsed
361     correctly.
362
363 Tree views
364 ----------
365
366 Tree views, also called list views, display records in a tabular form.
367
368 Their root element is ``<tree>``. The simplest form of the tree view simply
369 lists all the fields to display in the table (each field as a column):
370
371 .. code-block:: xml
372
373     <tree string="Idea list">
374         <field name="name"/>
375         <field name="inventor_id"/>
376     </tree>
377
378 Form views
379 ----------
380
381 Forms are used to create and edit single records.
382
383
384 Their root element is ``<form>``. They composed of high-level structure
385 elements (groups, notebooks) and interactive elements (buttons and fields):
386
387 .. code-block:: xml
388
389     <form string="Idea form">
390         <group colspan="4">
391             <group colspan="2" col="2">
392                 <separator string="General stuff" colspan="2"/>
393                 <field name="name"/>
394                 <field name="inventor_id"/>
395             </group>
396
397             <group colspan="2" col="2">
398                 <separator string="Dates" colspan="2"/>
399                 <field name="active"/>
400                 <field name="invent_date" readonly="1"/>
401             </group>
402
403             <notebook colspan="4">
404                 <page string="Description">
405                     <field name="description" nolabel="1"/>
406                 </page>
407             </notebook>
408
409             <field name="state"/>
410         </group>
411     </form>
412
413 .. exercise:: Customise form view using XML
414
415     Create your own form view for the Course object. Data displayed should be:
416     the name and the description of the course.
417
418     .. only:: solutions
419
420         .. patch::
421
422 .. exercise:: Notebooks
423
424     In the Course form view, put the description field under a tab, such that
425     it will be easier to add other tabs later, containing additional
426     information.
427
428     .. only:: solutions
429
430         Modify the Course form view as follows:
431
432         .. patch::
433
434 Form views can also use plain HTML for more flexible layouts:
435
436 .. code-block:: xml
437
438     <form string="Idea Form">
439         <header>
440             <button string="Confirm" type="object" name="action_confirm"
441                     states="draft" class="oe_highlight" />
442             <button string="Mark as done" type="object" name="action_done"
443                     states="confirmed" class="oe_highlight"/>
444             <button string="Reset to draft" type="object" name="action_draft"
445                     states="confirmed,done" />
446             <field name="state" widget="statusbar"/>
447         </header>
448         <sheet>
449             <div class="oe_title">
450                 <label for="name" class="oe_edit_only" string="Idea Name" />
451                 <h1><field name="name" /></h1>
452             </div>
453             <separator string="General" colspan="2" />
454             <group colspan="2" col="2">
455                 <field name="description" placeholder="Idea description..." />
456             </group>
457         </sheet>
458     </form>
459
460 Search views
461 ------------
462
463 Search views customize the search field associated with the list view (and
464 other aggregated views). Their root element is ``<search>`` and they're
465 composed of fields defining which fields can be searched on:
466
467 .. code-block:: xml
468
469     <search>
470         <field name="name"/>
471         <field name="inventor_id"/>
472     </search>
473
474 If no search view exists for the model, Odoo generates one which only allows
475 searching on the ``name`` field.
476
477 .. exercise:: Search courses
478
479     Allow searching for courses based on their title or their description.
480
481     .. only:: solutions
482
483         .. patch::
484
485 Relations between models
486 ========================
487
488 A record from a model may be related to a record from another model. For
489 instance, a sale order record is related to a client record that contains the
490 client data; it is also related to its sale order line records.
491
492 .. exercise:: Create a session model
493
494     For the module Open Academy, we consider a model for *sessions*: a session
495     is an occurrence of a course taught at a given time for a given audience.
496
497     Create a model for *sessions*. A session has a name, a start date, a
498     duration and a number of seats. Add an action and a menu item to display
499     them.
500
501     .. only:: solutions
502
503         Create the class *Session* in ``openacademy/models.py``.
504
505         .. patch::
506
507         .. note:: ``digits=(6, 2)`` specifies the precision of a float number:
508                   6 is the total number of digits, while 2 is the number of
509                   digits after the comma. Note that it results in the number
510                   digits before the comma is a maximum 4
511
512 Relational fields
513 -----------------
514
515 Relational fields link records, either of the same model (hierarchies) or
516 between different models.
517
518 Relational field types are:
519
520 :class:`Many2one(other_model, ondelete='set null') <openerp.fields.Many2one>`
521     A simple link to an other object::
522
523         print foo.other_id.name
524
525     .. seealso:: `foreign keys <http://www.postgresql.org/docs/9.3/static/tutorial-fk.html>`_
526
527 :class:`One2many(other_model, related_field) <openerp.fields.One2many>`
528     A virtual relationship, inverse of a :class:`~openerp.fields.Many2one`.
529     A :class:`~openerp.fields.One2many` behaves as a container of records,
530     accessing it results in a (possibly empty) set of records::
531
532         for other in foo.other_ids:
533             print foo.name
534
535     .. danger::
536
537         Because a :class:`~openerp.fields.One2many` is a virtual relationship,
538         there *must* be a :class:`~openerp.fields.Many2one` field in the
539         :samp:`{other_model}`, and its name *must* be :samp:`{related_field}`
540
541 :class:`Many2many(other_model) <openerp.fields.Many2many>`
542     Bidirectional multiple relationship, any record on one side can be related
543     to any number of records on the other side. Behaves as a container of
544     records, accessing it also results in a possibly empty set of records::
545
546         for other in foo.other_ids:
547             print foo.name
548
549 .. exercise:: Many2one relations
550
551     Using a many2one, modify the *Course* and *Session* models to reflect their
552     relation with other models:
553
554     - A course has a *responsible* user; the value of that field is a record of
555       the built-in model ``res.users``.
556     - A session has an *instructor*; the value of that field is a record of the
557       built-in model ``res.partner``.
558     - A session is related to a *course*; the value of that field is a record
559       of the model ``openacademy.course`` and is required.
560
561     .. only:: solutions
562
563         #. Add the relevant ``Many2one`` fields to the models, and
564         #. add access to the session object in
565            ``openacademy/view/openacademy.xml``.
566
567         .. patch::
568
569 .. exercise:: Inverse one2many relations
570
571     Using the inverse relational field one2many, modify the models to reflect
572     the relation between courses and sessions.
573
574     .. only:: solutions
575
576         Modify the ``Course`` class as follows:
577
578         .. patch::
579
580 .. exercise:: Multiple many2many relations
581
582     Using the relational field many2many, modify the *Session* model to relate
583     every session to a set of *attendees*. Attendees will be represented by
584     partner records, so we will relate to the built-in model ``res.partner``.
585
586     .. only:: solutions
587
588         Modify the ``Session`` class as follows:
589
590         .. patch::
591
592 .. exercise:: Views modification
593
594     For the *Course* model,
595
596     * the name and instructor for the course should be displayed in the tree
597       view
598     * the form view should display the course name and responsible at
599       the top, followed by the course description in a tab and the course
600       sessions in a second tab
601
602     For the *Session* model,
603
604     * the name of the session and the session course should be displayed in
605       the tree view
606     * the form view should display all the session's fields
607
608     Try to lay out the form views so that they're clear and readable.
609
610     .. only:: solutions
611
612         .. patch::
613
614 Inheritance
615 ===========
616
617 Model inheritance
618 -----------------
619
620 Odoo provides two *inheritance* mechanisms to extend an existing model in a
621 modular way.
622
623 The first inheritance mechanism allows a module to modify the behavior of a
624 model defined in another module:
625
626 - add fields to a model,
627 - override the definition of fields on a model,
628 - add constraints to a model,
629 - add methods to a model,
630 - override existing methods on a model.
631
632 The second inheritance mechanism (delegation) allows to link every record of a
633 model to a record in a parent model, and provides transparent access to the
634 fields of the parent record.
635
636 .. image:: backend/inheritance_methods.png
637     :align: center
638
639 .. seealso::
640
641     * :attr:`~openerp.models.Model._inherit`
642     * :attr:`~openerp.models.Model._inherits`
643
644 View inheritance
645 ----------------
646
647 Instead of modifying existing views in place (by overwriting them), Odoo
648 provides view inheritance where children "extension" views are applied on top of
649 root views, and can add or remove content from their parent.
650
651 An extension view references its parent using the ``inherit_id`` field, and
652 instead of a single view its ``arch`` field is composed of any number of
653 ``xpath`` elements selecting and altering the content of their parent view:
654
655 .. code-block:: xml
656
657     <!-- improved idea categories list -->
658     <record id="idea_category_list2" model="ir.ui.view">
659         <field name="name">id.category.list2</field>
660         <field name="model">ir.ui.view</field>
661         <field name="inherit_id" ref="id_category_list"/>
662         <field name="arch" type="xml">
663             <!-- find field description inside tree, and add the field
664                  idea_ids after it -->
665             <xpath expr="/tree/field[@name='description']" position="after">
666               <field name="idea_ids" string="Number of ideas"/>
667             </xpath>
668         </field>
669     </record>
670
671 ``expr``
672     An XPath_ expression selecting a single element in the parent view.
673     Raises an error if it matches no element or more than one
674 ``position``
675     Operation to apply to the matched element:
676
677     ``inside``
678         appends ``xpath``'s body at the end of the matched element
679     ``replace``
680         replaces the matched element by the ``xpath``'s body
681     ``before``
682         inserts the ``xpath``'s body as a sibling before the matched element
683     ``after``
684         inserts the ``xpaths``'s body as a sibling after the matched element
685     ``attributes``
686         alters the attributes of the matched element using special
687         ``attribute`` elements in the ``xpath``'s body
688
689 .. exercise:: Alter existing content
690
691     * Using model inheritance, modify the existing *Partner* model to add an
692       ``instructor`` boolean field, and a many2many field that corresponds to
693       the session-partner relation
694     * Using view inheritance, display this fields in the partner form view
695
696     .. only:: solutions
697
698        .. note::
699
700            This is the opportunity to introduce the developer mode to
701            inspect the view, find its external ID and the place to put the
702            new field.
703
704        #. Create a file ``openacademy/partner.py`` and import it in
705           ``__init__.py``
706        #. Create a file ``openacademy/views/partner.xml`` and add it to
707           ``__openerp__.py``
708
709        .. patch::
710
711 Domains
712 #######
713
714 In Odoo, :ref:`reference/orm/domains` are values that encode conditions on
715 records. A domain is a  list of criteria used to select a subset of a model's
716 records. Each criteria is a triple with a field name, an operator and a value.
717
718 For instance, when used on the *Product* model the following domain selects
719 all *services* with a unit price over *1000*::
720
721     [('product_type', '=', 'service'), ('unit_price', '>', 1000)]
722
723 By default criteria are combined with an implicit AND. The logical operators
724 ``&`` (AND), ``|`` (OR) and ``!`` (NOT) can be used to explicitly combine
725 criteria. They are used in prefix position (the operator is inserted before
726 its arguments rather than between). For instance to select products "which are
727 services *OR* have a unit price which is *NOT* between 1000 and 2000"::
728
729     ['|',
730         ('product_type', '=', 'service'),
731         '!', '&',
732             ('unit_price', '>=', 1000),
733             ('unit_price', '<', 2000)]
734
735 A ``domain`` parameter can be added to relational fields to limit valid
736 records for the relation when trying to select records in the client interface.
737
738 .. exercise:: Domains on relational fields
739
740     When selecting the instructor for a *Session*, only instructors (partners
741     with ``instructor`` set to ``True``) should be visible.
742
743     .. only:: solutions
744
745         .. patch::
746
747         .. note::
748
749             A domain declared as a literal list is evaluated server-side and
750             can't refer to dynamic values on the right-hand side, a domain
751             declared as a string is evaluated client-side and allows
752             field names on the right-hand side
753
754 .. exercise:: More complex domains
755
756     Create new partner categories *Teacher / Level 1* and *Teacher / Level 2*.
757     The instructor for a session can be either an instructor or a teacher
758     (of any level).
759
760     .. only:: solutions
761
762         #. Modify the *Session* model's domain
763         #. Modify ``openacademy/view/partner.xml`` to get access to
764            *Partner categories*:
765
766         .. patch::
767
768 Computed fields and default values
769 ==================================
770
771 So far fields have been stored directly in and retrieved directly from the
772 database. Fields can also be *computed*. In that case, the field's value is not
773 retrieved from the database but computed on-the-fly by calling a method of the
774 model.
775
776 To create a computed field, create a field and set its attribute
777 :attr:`~openerp.fields.Field.compute` to the name of a method. The computation
778 method should simply set the value of the field to compute on every record in
779 ``self``.
780
781 .. danger:: ``self`` is a collection
782     :class: aphorism
783
784     The object ``self`` is a *recordset*, i.e., an ordered collection of
785     records. It supports the standard Python operations on collections, like
786     ``len(self)`` and ``iter(self)``, plus extra set operations like ``recs1 +
787     recs2``.
788
789     Iterating over ``self`` gives the records one by one, where each record is
790     itself a collection of size 1. You can access/assign fields on single
791     records by using the dot notation, like ``record.name``.
792
793 .. code-block:: python
794
795     import random
796     from openerp import models, fields
797
798     class ComputedModel(models.Model):
799         _name = 'test.computed'
800
801         name = fields.Char(compute='_compute_name')
802
803         def _compute_name(self):
804             for record in self:
805                 record.name = str(random.randint(1, 1e6))
806
807 Our compute method is very simple: it loops over ``self`` and performs the same
808 operation on every record. We can make it slightly simpler by using the
809 decorator :func:`~openerp.api.one` to automatically loop on the collection::
810
811         @api.one
812         def _compute_name(self):
813             self.name = str(random.randint(1, 1e6))
814
815 Dependencies
816 ------------
817
818 The value of a computed field usually depends on the values of other fields on
819 the computed record. The ORM expects the developer to specify those dependencies
820 on the compute method with the decorator :func:`~openerp.api.depends`.
821 The given dependencies are used by the ORM to trigger the recomputation of the
822 field whenever some of its dependencies have been modified::
823
824     from openerp import models, fields, api
825
826     class ComputedModel(models.Model):
827         _name = 'test.computed'
828
829         name = fields.Char(compute='_compute_name')
830         value = fields.Integer()
831
832         @api.one
833         @api.depends('value')
834         def _compute_name(self):
835             self.name = "Record with value %s" % self.value
836
837 .. exercise:: Computed fields
838
839     * Add the percentage of taken seats to the *Session* model
840     * Display that field in the tree and form views
841     * Display the field as a progress bar
842
843     .. only:: solutions
844
845         #. Add a computed field to *Session*
846         #. Show the field in the *Session* view:
847
848         .. patch::
849
850 Default values
851 --------------
852
853 Any field can be given a default value. In the field definition, add the option
854 ``default=X`` where ``X`` is either a Python literal value (boolean, integer,
855 float, string), or a function taking a recordset and returning a value::
856
857     name = fields.Char(default="Unknown")
858     user_id = fields.Many2one('res.users', default=lambda self: self.env.user)
859
860 .. exercise:: Active objects – Default values
861
862     * Define the start_date default value as today (see
863       :class:`~openerp.fields.Date`).
864     * Add a field ``active`` in the class Session, and set sessions as active by
865       default.
866
867     .. only:: solutions
868
869         .. patch::
870
871         .. note::
872
873             Odoo has built-in rules making fields with an ``active`` field set
874             to ``False`` invisible.
875
876 Onchange
877 ========
878
879 The "onchange" mechanism provides a way for the client interface to update a
880 form whenever the user has filled in a value in a field, without saving anything
881 to the database.
882
883 For instance, suppose a model has three fields ``amount``, ``unit_price`` and
884 ``price``, and you want to update the price on the form when any of the other
885 fields is modified. To achieve this, define a method where ``self`` represents
886 the record in the form view, and decorate it with :func:`~openerp.api.onchange`
887 to specify on which field it has to be triggered. Any change you make on
888 ``self`` will be reflected on the form.
889
890 .. code-block:: xml
891
892     <!-- content of form view -->
893     <field name="amount"/>
894     <field name="unit_price"/>
895     <field name="price" readonly="1"/>
896
897 .. code-block:: python
898
899     # onchange handler
900     @api.onchange('amount', 'unit_price')
901     def _onchange_price(self):
902         # set auto-changing field
903         self.price = self.amount * self.unit_price
904         # Can optionally return a warning and domains
905         return {
906             'warning': {
907                 'title': "Something bad happened",
908                 'message': "It was very bad indeed",
909             }
910         }
911
912 For computed fields, valued ``onchange`` behavior is built-in as can be seen by
913 playing with the *Session* form: change the number of seats or participants, and
914 the ``taken_seats`` progressbar is automatically updated.
915
916 .. exercise:: Warning
917
918     Add an explicit onchange to warn about invalid values, like a negative
919     number of seats, or more participants than seats.
920
921     .. only:: solutions
922
923         .. patch::
924
925 Model constraints
926 =================
927
928 Odoo provides two ways to set up automatically verified invariants:
929 :func:`Python constraints <openerp.api.constrains>` and
930 :attr:`SQL constaints <openerp.models.Model._sql_constraints>`.
931
932 A Python constraint is defined as a method decorated with
933 :func:`~openerp.api.constrains`, and invoked on a recordset. The decorator
934 specifies which fields are involved in the constraint, so that the constraint is
935 automatically evaluated when one of them is modified. The method is expected to
936 raise an exception if its invariant is not satisfied::
937
938     from openerp.exceptions import ValidationError
939
940     @api.constrains('age')
941     def _check_something(self):
942         for record in self:
943             if record.age > 20:
944                 raise ValidationError("Your record is too old: %s" % record.age)
945         # all records passed the test, don't return anything
946
947 .. exercise:: Add Python constraints
948
949     Add a constraint that checks that the instructor is not present in the
950     attendees of his/her own session.
951
952     .. only:: solutions
953
954         .. patch::
955
956 SQL constraints are defined through the model attribute
957 :attr:`~openerp.models.Model._sql_constraints`. The latter is assigned to a list
958 of triples of strings ``(name, sql_definition, message)``, where ``name`` is a
959 valid SQL constraint name, ``sql_definition`` is a table_constraint_ expression,
960 and ``message`` is the error message.
961
962 .. exercise:: Add SQL constraints
963
964     With the help of `PostgreSQL's documentation`_ , add the following
965     constraints:
966
967     #. CHECK that the course description and the course title are different
968     #. Make the Course's name UNIQUE
969
970     .. only:: solutions
971
972         .. patch::
973
974 .. exercise:: Exercise 6 - Add a duplicate option
975
976     Since we added a constraint for the Course name uniqueness, it is not
977     possible to use the "duplicate" function anymore (:menuselection:`Form -->
978     Duplicate`).
979
980     Re-implement your own "copy" method which allows to duplicate the Course
981     object, changing the original name into "Copy of [original name]".
982
983     .. only:: solutions
984
985         .. patch::
986
987 Advanced Views
988 ==============
989
990 Tree views
991 ----------
992
993 Tree views can take supplementary attributes to further customize their
994 behavior:
995
996 ``colors``
997     mappings of colors to conditions. If the condition evaluates to ``True``,
998     the corresponding color is applied to the row:
999
1000     .. code-block:: xml
1001
1002         <tree string="Idea Categories" colors="blue:state=='draft';red:state=='trashed'">
1003             <field name="name"/>
1004             <field name="state"/>
1005         </tree>
1006
1007     Clauses are separated by ``;``, the color and condition are separated by
1008     ``:``.
1009
1010 ``editable``
1011     Either ``"top"`` or ``"bottom"``. Makes the tree view editable in-place
1012     (rather than having to go through the form view), the value is the
1013     position where new rows appear.
1014
1015 .. exercise:: List coloring
1016
1017     Modify the Session tree view in such a way that sessions lasting less than
1018     5 days are colored blue, and the ones lasting more than 15 days are
1019     colored red.
1020
1021     .. only:: solutions
1022
1023         Modify the session tree view:
1024
1025         .. patch::
1026
1027 Calendars
1028 ---------
1029
1030 Displays records as calendar events. Their root element is ``<calendar>`` and
1031 their most common attributes are:
1032
1033 ``color``
1034     The name of the field used for *color segmentation*. Colors are
1035     automatically distributed to events, but events in the same color segment
1036     (records which have the same value for their ``@color`` field) will be
1037     given the same color.
1038 ``date_start``
1039     record's field holding the start date/time for the event
1040 ``date_stop`` (optional)
1041     record's field holding the end date/time for the event
1042
1043 field (to define the label for each calendar event)
1044
1045 .. code-block:: xml
1046
1047     <calendar string="Ideas" date_start="invent_date" color="inventor_id">
1048         <field name="name"/>
1049     </calendar>
1050
1051 .. exercise:: Calendar view
1052
1053     Add a Calendar view to the *Session* model enabling the user to view the
1054     events associated to the Open Academy.
1055
1056     .. only:: solutions
1057
1058         #. Add an ``end_date`` field computed from ``start_date`` and
1059            ``duration``
1060
1061            .. tip:: the inverse function makes the field writable, and allows
1062                     moving the sessions (via drag and drop) in the calendar view
1063
1064         #. Add a calendar view to the *Session* model
1065         #. And add the calendar view to the *Session* model's actions
1066
1067         .. patch::
1068
1069 Search views
1070 ------------
1071
1072 Search view fields can take custom operators or :ref:`reference/orm/domains`
1073 for more flexible matching of results.
1074
1075 Search views can also contain *filters* which act as toggles for predefined
1076 searches (defined using :ref:`reference/orm/domains`):
1077
1078 .. code-block:: xml
1079
1080     <search string="Ideas">
1081         <filter name="my_ideas" domain="[('inventor_id','=',uid)]"
1082                 string="My Ideas" icon="terp-partner"/>
1083         <field name="name"/>
1084         <field name="description"/>
1085         <field name="inventor_id"/>
1086         <field name="country_id" widget="selection"/>
1087     </search>
1088
1089 To use a non-default search view in an action, it should be linked using the
1090 ``search_view_id`` field of the action record.
1091
1092 The action can also set default values for search fields through its
1093 ``context`` field: context keys of the form
1094 :samp:`search_default_{field_name}` will initialize *field_name* with the
1095 provided value. Search filters must have an optional ``@name`` to have a
1096 default and behave as booleans (they can only be enabled by default).
1097
1098 .. exercise:: Search views
1099
1100     Add a button to filter the courses for which the current user is the
1101     responsible in the course search view. Make it selected by default.
1102
1103     .. only:: solutions
1104
1105         .. patch::
1106
1107 Gantt
1108 -----
1109
1110 Horizontal bar charts typically used to show project planning and advancement,
1111 their root element is ``<gantt>``.
1112
1113 .. code-block:: xml
1114
1115     <gantt string="Ideas" date_start="invent_date" color="inventor_id">
1116         <level object="idea.idea" link="id" domain="[]">
1117             <field name="inventor_id"/>
1118         </level>
1119     </gantt>
1120
1121 .. exercise:: Gantt charts
1122
1123     Add a Gantt Chart enabling the user to view the sessions scheduling linked
1124     to the Open Academy module. The sessions should be grouped by instructor.
1125
1126     .. only:: solutions
1127
1128         #. Create a computed field expressing the session's duration in hours
1129         #. Add the gantt view's definition, and add the gantt view to the
1130            *Session* model's action
1131
1132         .. patch::
1133
1134 Graph views
1135 -----------
1136
1137 Graph views allow aggregated overview and analysis of models, their root
1138 element is ``<graph>``.
1139
1140 Graph views have 4 display modes, the default mode is selected using the
1141 ``@type`` attribute.
1142
1143 Pivot
1144     a multidimensional table, allows the selection of filers and dimensions
1145     to get the right aggregated dataset before moving to a more graphical
1146     overview
1147 Bar (default)
1148     a bar chart, the first dimension is used to define groups on the
1149     horizontal axis, other dimensions define aggregated bars within each group.
1150
1151     By default bars are side-by-side, they can be stacked by using
1152     ``@stacked="True"`` on the ``<graph>``
1153 Line
1154     2-dimensional line chart
1155 Pie
1156     2-dimensional pie
1157
1158 Graph views contain ``<field>`` with a mandatory ``@type`` attribute taking
1159 the values:
1160
1161 ``row`` (default)
1162     the field should be aggregated by default
1163 ``measure``
1164     the field should be aggregated rather than grouped on
1165
1166 .. code-block:: xml
1167
1168     <graph string="Total idea score by Inventor">
1169         <field name="inventor_id"/>
1170         <field name="score" type="measure"/>
1171     </graph>
1172
1173 .. warning::
1174
1175     Graph views perform aggregations on database values, they do not work
1176     with non-stored computed fields.
1177
1178 .. exercise:: Graph view
1179
1180     Add a Graph view in the Session object that displays, for each course, the
1181     number of attendees under the form of a bar chart.
1182
1183     .. only:: solutions
1184
1185         #. Add the number of attendees as a stored computed field
1186         #. Then add the relevant view
1187
1188         .. patch::
1189
1190 Kanban
1191 ------
1192
1193 Used to organize tasks, production processes, etc… their root element is
1194 ``<kanban>``.
1195
1196 A kanban view shows a set of cards possibly grouped in columns. Each card
1197 represents a record, and each column the values of an aggregation field.
1198
1199 For instance, project tasks may be organized by stage (each column is a
1200 stage), or by responsible (each column is a user), and so on.
1201
1202 Kanban views define the structure of each card as a mix of form elements
1203 (including basic HTML) and :ref:`reference/qweb`.
1204
1205 .. exercise:: Kanban view
1206
1207     Add a Kanban view that displays sessions grouped by course (columns are
1208     thus courses).
1209
1210     .. only:: solutions
1211
1212         #. Add an integer ``color`` field to the *Session* model
1213         #. Add the kanban view and update the action
1214
1215         .. patch::
1216
1217 Workflows
1218 =========
1219
1220 Workflows are models associated to business objects describing their dynamics.
1221 Workflows are also used to track processes that evolve over time.
1222
1223 .. exercise:: Almost a workflow
1224
1225     Add a ``state`` field to the *Session* model. It will be used to define
1226     a workflow-ish.
1227
1228     A sesion can have three possible states: Draft (default), Confirmed and
1229     Done.
1230
1231     In the session form, add a (read-only) field to
1232     visualize the state, and buttons to change it. The valid transitions are:
1233
1234     * Draft ➔ Confirmed
1235     * Confirmed ➔ Draft
1236     * Confirmed ➔ Done
1237     * Done ➔ Draft
1238
1239     .. only:: solutions
1240
1241         #. Add a new ``state`` field
1242         #. Add state-transitioning methods, those can be called from view
1243            buttons to change the record's state
1244         #. And add the relevant buttons to the session's form view
1245
1246         .. patch::
1247
1248 Workflows may be associated with any object in Odoo, and are entirely
1249 customizable. Workflows are used to structure and manage the lifecycles of
1250 business objects and documents, and define transitions, triggers, etc. with
1251 graphical tools. Workflows, activities (nodes or actions) and transitions
1252 (conditions) are declared as XML records, as usual. The tokens that navigate
1253 in workflows are called workitems.
1254
1255 .. exercise:: Workflow
1256
1257     Replace the ad-hoc *Session* workflow by a real workflow. Transform the
1258     *Session* form view so its buttons call the workflow instead of the
1259     model's methods.
1260
1261     .. only:: solutions
1262
1263         .. patch::
1264
1265         .. warning::
1266
1267             A workflow associated with a model is only created when the
1268             model's records are created. Thus there is no workflow instance
1269             associated with session instances created before the workflow's
1270             definition
1271
1272         .. tip::
1273
1274             In order to check if instances of the workflow are correctly
1275             created alongside sessions, go to :menuselection:`Settings -->
1276             Technical --> Workflows --> Instances`
1277
1278
1279
1280 .. exercise:: Automatic transitions
1281
1282     Automatically transition sessions from *Draft* to *Confirmed* when more
1283     than half the session's seats are reserved.
1284
1285     .. only:: solutions
1286
1287         .. patch::
1288
1289 .. exercise:: Server actions
1290
1291     Replace the Python methods for synchronizing session state by
1292     server actions.
1293
1294     Both the workflow and the server actions could have been created entirely
1295     from the UI.
1296
1297     .. only:: solutions
1298
1299         .. patch::
1300
1301 Security
1302 ========
1303
1304 Access control mechanisms must be configured to achieve a coherent security
1305 policy.
1306
1307 Group-based access control mechanisms
1308 -------------------------------------
1309
1310 Groups are created as normal records on the model “res.groups”, and granted
1311 menu access via menu definitions. However even without a menu, objects may
1312 still be accessible indirectly, so actual object-level permissions (read,
1313 write, create, unlink) must be defined for groups. They are usually inserted
1314 via CSV files inside modules. It is also possible to restrict access to
1315 specific fields on a view or object using the field's groups attribute.
1316
1317 Access rights
1318 -------------
1319
1320 Access rights are defined as records of the model “ir.model.access”. Each
1321 access right is associated to a model, a group (or no group for global
1322 access), and a set of permissions: read, write, create, unlink. Such access
1323 rights are usually created by a CSV file named after its model:
1324 ``ir.model.access.csv``.
1325
1326 .. code-block:: text
1327
1328     id,name,model_id/id,group_id/id,perm_read,perm_write,perm_create,perm_unlink
1329     access_idea_idea,idea.idea,model_idea_idea,base.group_user,1,1,1,0
1330     access_idea_vote,idea.vote,model_idea_vote,base.group_user,1,1,1,0
1331
1332 .. exercise:: Add access control through the OpenERP interface
1333
1334     Create a new user "John Smith". Then create a group
1335     "OpenAcademy / Session Read" with read access to the *Session* model.
1336
1337     .. only:: solutions
1338
1339         #. Create a new user *John Smith* through
1340            :menuselection:`Settings --> Users --> Users`
1341         #. Create a new group ``session_read`` through
1342            :menuselection:`Settings --> Users --> Groups`, it should have
1343            read access on the *Session* model
1344         #. Edit *John Smith* to make them a member of ``session_read``
1345         #. Log in as *John Smith* to check the access rights are correct
1346
1347 .. exercise:: Add access control through data files in your module
1348
1349     Using data files,
1350
1351     * Create a group *OpenAcademy / Manager* with full access to all
1352       OpenAcademy models
1353     * Make *Session* and *Course* readable by all users
1354
1355     .. only:: solutions
1356
1357         #. Create a new file ``openacademy/security/security.xml`` to
1358            hold the OpenAcademy Manager group
1359         #. Edit the file ``openacademy/security/ir.model.access.csv`` with
1360            the access rights to the models
1361         #. Finally update ``openacademy/__openerp__.py`` to add the new data
1362            files to it
1363
1364         .. patch::
1365
1366 Record rules
1367 ------------
1368
1369 A record rule restricts the access rights to a subset of records of the given
1370 model. A rule is a record of the model “ir.rule”, and is associated to a
1371 model, a number of groups (many2many field), permissions to which the
1372 restriction applies, and a domain. The domain specifies to which records the
1373 access rights are limited.
1374
1375 Here is an example of a rule that prevents the deletion of leads that are not
1376 in state “cancel”. Notice that the value of the field “groups” must follow
1377 the same convention as the method “write” of the ORM.
1378
1379 .. code-block:: xml
1380
1381     <record id="delete_cancelled_only" model="ir.rule">
1382         <field name="name">Only cancelled leads may be deleted</field>
1383         <field name="model_id" ref="crm.model_crm_lead"/>
1384         <field name="groups" eval="[(4, ref('base.group_sale_manager'))]"/>
1385         <field name="perm_read" eval="0"/>
1386         <field name="perm_write" eval="0"/>
1387         <field name="perm_create" eval="0"/>
1388         <field name="perm_unlink" eval="1" />
1389         <field name="domain_force">[('state','=','cancel')]</field>
1390     </record>
1391
1392 .. exercise:: Record rule
1393
1394     Add a record rule for the model Course and the group
1395     "OpenAcademy / Manager", that restricts ``write`` and ``unlink`` accesses
1396     to the responsible of a course. If a course has no responsible, all users
1397     of the group must be able to modify it.
1398
1399     .. only:: solutions
1400
1401         Create a new rule in ``openacademy/security/security.xml``:
1402
1403         .. patch::
1404
1405 Internationalization
1406 ====================
1407
1408 Each module can provide its own translations within the i18n directory, by
1409 having files named LANG.po where LANG is the locale code for the language, or
1410 the language and country combination when they differ (e.g. pt.po or
1411 pt_BR.po). Translations will be loaded automatically by Odoo for all
1412 enabled languages. Developers always use English when creating a module, then
1413 export the module terms using Odoo's gettext POT export feature
1414 (:menuselection:`Settings --> Translations --> Import/Export --> Export
1415 Translation` without specifying a language), to create the module template POT
1416 file, and then derive the translated PO files. Many IDE's have plugins or modes
1417 for editing and merging PO/POT files.
1418
1419 .. tip:: The GNU gettext format (Portable Object) used by Odoo is
1420          integrated into LaunchPad, making it an online collaborative
1421          translation platform.
1422
1423 .. code-block:: text
1424
1425    |- idea/ # The module directory
1426       |- i18n/ # Translation files
1427          | - idea.pot # Translation Template (exported from Odoo)
1428          | - fr.po # French translation
1429          | - pt_BR.po # Brazilian Portuguese translation
1430          | (...)
1431
1432 .. tip:: 
1433
1434    By default Odoo's POT export only extracts labels inside XML files or
1435    inside field definitions in Python code, but any Python string can be
1436    translated this way by surrounding it with the function :func:`openerp._`
1437    (e.g. ``_("Label")``)
1438
1439 .. exercise:: Translate a module
1440
1441    Choose a second language for your Odoo installation. Translate your
1442    module using the facilities provided by Odoo.
1443
1444    .. only:: solutions
1445
1446         #. Create a directory ``openacademy/i18n/``
1447         #. Install whichever language you want (
1448            :menuselection:`Administration --> Translations --> Load an
1449            Official Translation`)
1450         #. Synchronize translatable terms (:menuselection:`Administration -->
1451            Translations --> Application Terms --> Synchronize Translations`)
1452         #. Create a template translation file by exporting (
1453            :menuselection:`Administration --> Translations -> Import/Export
1454            --> Export Translation`) without specifying a language, save in
1455            ``openacademy/i18n/``
1456         #. Create a translation file by exporting (
1457            :menuselection:`Administration --> Translations --> Import/Export
1458            --> Export Translation`) and specifying a language. Save it in
1459            ``openacademy/i18n/``
1460         #. Open the exported translation file (with a basic text editor or a
1461            dedicated PO-file editor e.g. POEdit_ and translate the missing
1462            terms
1463
1464         #. Add ``from openerp import _`` to ``course.py`` and
1465            mark missing strings as translatable
1466
1467         #. Repeat steps 3-6
1468
1469         .. patch::
1470
1471         .. todo:: do we never reload translations?
1472
1473
1474 Reporting
1475 =========
1476
1477 Printed reports
1478 ---------------
1479
1480 Odoo 8.0 comes with a new report engine based on :ref:`reference/qweb`,
1481 `Twitter Bootstrap`_ and Wkhtmltopdf_. 
1482
1483 A report is a combination two elements:
1484
1485 * an ``ir.actions.report.xml``, for which a ``<report>`` shortcut element is
1486   provided, it sets up various basic parameters for the report (default
1487   type, whether the report should be saved to the database after generation,…)
1488
1489
1490   .. code-block:: xml
1491
1492       <report
1493           id="account_invoices"
1494           model="account.invoice"
1495           string="Invoices"
1496           report_type="qweb-pdf"
1497           name="account.report_invoice"
1498           file="account.report_invoice"
1499           attachment_use="True"
1500           attachment="(object.state in ('open','paid')) and
1501               ('INV'+(object.number or '').replace('/','')+'.pdf')"
1502       />
1503
1504 * A standard :ref:`QWeb view <reference/views/qweb>` for the actual report:
1505
1506   .. code-block:: xml
1507
1508     <t t-call="report.html_container">
1509         <t t-foreach="docs" t-as="o">
1510             <t t-call="report.external_layout">
1511                 <div class="page">
1512                     <h2>Report title</h2>
1513                 </div>
1514             </t>
1515         </t>
1516     </t>
1517
1518     the standard rendering context provides a number of elements, the most
1519     important being:
1520
1521     ``docs``
1522         the records for which the report is printed
1523     ``user``
1524         the user printing the report
1525
1526 Because reports are standard web pages, they are available through a URL and
1527 output parameters can be manipulated through this URL, for instance the HTML
1528 version of the *Invoice* report is available through
1529 http://localhost:8069/report/html/account.report_invoice/1 (if ``account`` is
1530 installed) and the PDF version through
1531 http://localhost:8069/report/pdf/account.report_invoice/1.
1532
1533 .. exercise:: Create a report for the Session model
1534
1535    For each session, it should display session's name, its start and end,
1536    and list the session's attendees.
1537
1538    .. only:: solutions
1539
1540         .. patch::
1541
1542 Dashboards
1543 ----------
1544
1545 .. exercise:: Define a Dashboard
1546
1547    Define a dashboard containing the graph view you created, the sessions
1548    calendar view and a list view of the courses (switchable to a form
1549    view). This dashboard should be available through a menuitem in the menu,
1550    and automatically displayed in the web client when the OpenAcademy main
1551    menu is selected.
1552
1553    .. only:: solutions
1554
1555         #. Create a file ``openacademy/views/session_board.xml``. It should contain
1556            the board view, the actions referenced in that view, an action to
1557            open the dashboard and a re-definition of the main menu item to add
1558            the dashboard action
1559
1560            .. note:: Available dashboard styles are ``1``, ``1-1``, ``1-2``,
1561                      ``2-1`` and ``1-1-1``
1562
1563         #. Update ``openacademy/__openerp__.py`` to reference the new data
1564            file
1565
1566         .. patch::
1567
1568 WebServices
1569 ===========
1570
1571 The web-service module offer a common interface for all web-services :
1572
1573 - XML-RPC
1574 - JSON-RPC
1575
1576 Business objects can also be accessed via the distributed object
1577 mechanism. They can all be modified via the client interface with contextual
1578 views.
1579
1580 Odoo is accessible through XML-RPC/JSON-RPC interfaces, for which libraries
1581 exist in many languages.
1582
1583 XML-RPC Library
1584 ---------------
1585
1586 The following example is a Python program that interacts with an Odoo
1587 server with the library xmlrpclib.
1588
1589 ::
1590
1591    import xmlrpclib
1592
1593    root = 'http://%s:%d/xmlrpc/' % (HOST, PORT)
1594
1595    uid = xmlrpclib.ServerProxy(root + 'common').login(db, username, password)
1596    print "Logged in as %s (uid: %d)" % (USER, uid)
1597
1598    # Create a new idea
1599    sock = xmlrpclib.ServerProxy(root + 'object')
1600    args = {
1601        'name' : 'Another idea',
1602        'description' : 'This is another idea of mine',
1603        'inventor_id': uid,
1604    }
1605    idea_id = sock.execute(db, uid, password, 'idea.idea', 'create', args)
1606
1607 .. exercise:: Add a new service to the client
1608
1609    Write a Python program able to send XML-RPC requests to a PC running
1610    Odoo (yours, or your instructor's). This program should display all
1611    the sessions, and their corresponding number of seats. It should also
1612    create a new session for one of the courses.
1613
1614    .. only:: solutions
1615
1616         .. code-block:: python
1617
1618             import functools
1619             import xmlrpclib
1620             HOST = 'localhost'
1621             PORT = 8069
1622             DB = 'openacademy'
1623             USER = 'admin'
1624             PASS = 'admin'
1625             ROOT = 'http://%s:%d/xmlrpc/' % (HOST,PORT)
1626
1627             # 1. Login
1628             uid = xmlrpclib.ServerProxy(ROOT + 'common').login(DB,USER,PASS)
1629             print "Logged in as %s (uid:%d)" % (USER,uid)
1630
1631             call = functools.partial(
1632                 xmlcprlib.ServerProxy(ROOT + 'object').execute,
1633                 DB, uid, PASS)
1634
1635             # 2. Read the sessions
1636             sessions = call('openacademy.session','search_read', [], ['name','seats'])
1637             for session in sessions :
1638                 print "Session %s (%s seats)" % (session['name'], session['seats'])
1639             # 3.create a new session
1640             session_id = call('openacademy.session', 'create', {
1641                 'name' : 'My session',
1642                 'course_id' : 2,
1643             })
1644
1645         Instead of using a hard-coded course id, the code can look up a course
1646         by name::
1647
1648             # 3.create a new session for the "Functional" course
1649             course_id = call('openacademy.course', 'search', [('name','ilike','Functional')])[0]
1650             session_id = call('openacademy.session', 'create', {
1651                 'name' : 'My session',
1652                 'course_id' : course_id,
1653             })
1654
1655 .. note:: there are also a number of high-level APIs in various languages to
1656           access Odoo systems without *explicitly* going through XML-RPC e.g.
1657
1658     * https://github.com/akretion/ooor
1659     * https://github.com/syleam/openobject-library
1660     * https://github.com/nicolas-van/openerp-client-lib
1661     * https://pypi.python.org/pypi/oersted/
1662
1663 .. [#autofields] it is possible to :attr:`disable the automatic creation of some
1664                  fields <openerp.models.Model._log_access>`
1665 .. [#rawsql] writing raw SQL queries is possible, but requires care as it
1666              bypasses all Odoo authentication and security mechanisms.
1667
1668 .. _database index:
1669     http://use-the-index-luke.com/sql/preface
1670
1671 .. _POEdit: http://poedit.net
1672
1673 .. _PostgreSQL's documentation:
1674 .. _table_constraint:
1675     http://www.postgresql.org/docs/9.3/static/ddl-constraints.html
1676
1677 .. _python: http://python.org
1678
1679 .. _XPath: http://w3.org/TR/xpath
1680
1681 .. _twitter bootstrap: http://getbootstrap.com
1682
1683 .. _wkhtmltopdf: http://wkhtmltopdf.org