1 .. queue:: backend/series
7 Start/Stop the Odoo server
8 ==========================
10 Odoo uses a client/server architecture in which clients are web browsers
11 accessing the odoo server via RPC.
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.
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
25 The server is stopped by hitting ``Ctrl-C`` twice from the terminal, or by
26 killing the corresponding OS process.
31 Both server and client extensions are packaged as *modules* which are
32 optionally loaded in a *database*.
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.
39 Everything in Odoo thus starts and ends with modules.
41 Composition of a module
42 -----------------------
44 An Odoo module can contain a number of elements:
47 declared as Python classes, these resources are automatically persisted
48 by Odoo based on their configuration
51 XML or CSV files declaring metadata (views or workflows), configuration
52 data (modules parameterization), demonstration data and more
55 Handle requests from web browsers
58 Images, CSS or javascript files used by the web interface or website
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>`
70 most command-line options can also be set using :ref:`a configuration
71 file <reference/cmdline/config>`
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, …
78 The manifest's general structure is::
84 'author': "Author Name",
85 'category': 'Category',
89 # data files always loaded at installation
93 # data files containing optionally loaded demonstration data
100 `Python package <http://docs.python.org/2/tutorial/modules.html#packages>`_
101 with a ``__init__.py`` file, containing import instructions for various Python
104 For instance, if the module has a single ``mymodule.py`` file ``__init__.py``
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:
115 odoo.py scaffold <module name> <where to put it>
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.
121 .. exercise:: Module creation
123 Use the command line above to create an empty module Open Academy, and
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.
134 Object-Relational Mapping
135 -------------------------
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]_.
141 Business objects are declared as Python classes extending
142 :class:`~openerp.models.Model` which integrates them into the automated
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
151 from openerp import models
152 class MinimalModel(models.Model):
158 Fields are used to define what the model can store and where. Fields are
159 defined as attributes on the model class::
161 from openerp import models, fields
163 class LessMinimalModel(models.Model):
164 _name = 'test.model2'
171 Much like the model itself, its fields can be configured, by passing
172 configuration attributes as parameters::
174 name = field.Char(required=True)
176 Some attributes are available on all fields, here are the most common ones:
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
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).
195 Example of simple fields are :class:`~openerp.fields.Boolean`,
196 :class:`~openerp.fields.Date`, :class:`~openerp.fields.Char`.
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
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
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`.
223 .. exercise:: Define a model
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.
230 Edit the file ``openacademy/models.py`` to include a *Course* class.
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.
240 .. tip:: some modules exist solely to add data into Odoo
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
251 <record model="{model name}" id="{record identifier}">
252 <field name="{a field name}">{a value}</field>
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.
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).
267 .. exercise:: Define demonstration data
269 Create demonstration data filling the *Courses* model with a few
270 demonstration courses.
274 Edit the file ``openacademy/demo.xml`` to include some data.
281 Actions and menus are regular records in database, usually declared through
282 data files. Actions can be triggered in three ways:
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
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
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>
299 <menuitem id="menu_ideas" parent="menu_root" name="Ideas" sequence="10"
300 action="action_list_ideas"/>
305 The action must be declared before its corresponding menu in the XML file.
307 Data files are executed sequentially, the action's ``id`` must be present
308 in the database before the menu can be created.
310 .. exercise:: Define new menu entries
312 Define new menu entries to access courses and sessions under the
313 OpenAcademy menu entry. A user should be able to
315 - display a list of all the courses
316 - create/modify courses
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``
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
337 :ref:`View inheritance <reference/views/inheritance>` allows altering views
338 declared elsewhere (adding or removing content).
340 Generic view declaration
341 ------------------------
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:
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>, ... -->
357 .. danger:: The view's content is XML.
360 The ``arch`` field must thus be declared as ``type="xml"`` to be parsed
366 Tree views, also called list views, display records in a tabular form.
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):
373 <tree string="Idea list">
375 <field name="inventor_id"/>
381 Forms are used to create and edit single records.
384 Their root element is ``<form>``. They composed of high-level structure
385 elements (groups, notebooks) and interactive elements (buttons and fields):
389 <form string="Idea form">
391 <group colspan="2" col="2">
392 <separator string="General stuff" colspan="2"/>
394 <field name="inventor_id"/>
397 <group colspan="2" col="2">
398 <separator string="Dates" colspan="2"/>
399 <field name="active"/>
400 <field name="invent_date" readonly="1"/>
403 <notebook colspan="4">
404 <page string="Description">
405 <field name="description" nolabel="1"/>
409 <field name="state"/>
413 .. exercise:: Customise form view using XML
415 Create your own form view for the Course object. Data displayed should be:
416 the name and the description of the course.
422 .. exercise:: Notebooks
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
430 Modify the Course form view as follows:
434 Form views can also use plain HTML for more flexible layouts:
438 <form string="Idea Form">
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"/>
449 <div class="oe_title">
450 <label for="name" class="oe_edit_only" string="Idea Name" />
451 <h1><field name="name" /></h1>
453 <separator string="General" colspan="2" />
454 <group colspan="2" col="2">
455 <field name="description" placeholder="Idea description..." />
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:
471 <field name="inventor_id"/>
474 If no search view exists for the model, Odoo generates one which only allows
475 searching on the ``name`` field.
477 .. exercise:: Search courses
479 Allow searching for courses based on their title or their description.
485 Relations between models
486 ========================
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.
492 .. exercise:: Create a session model
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.
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
503 Create the class *Session* in ``openacademy/models.py``.
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
515 Relational fields link records, either of the same model (hierarchies) or
516 between different models.
518 Relational field types are:
520 :class:`Many2one(other_model, ondelete='set null') <openerp.fields.Many2one>`
521 A simple link to an other object::
523 print foo.other_id.name
525 .. seealso:: `foreign keys <http://www.postgresql.org/docs/9.3/static/tutorial-fk.html>`_
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::
532 for other in foo.other_ids:
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}`
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::
546 for other in foo.other_ids:
549 .. exercise:: Many2one relations
551 Using a many2one, modify the *Course* and *Session* models to reflect their
552 relation with other models:
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.
563 #. Add the relevant ``Many2one`` fields to the models, and
564 #. add access to the session object in
565 ``openacademy/view/openacademy.xml``.
569 .. exercise:: Inverse one2many relations
571 Using the inverse relational field one2many, modify the models to reflect
572 the relation between courses and sessions.
576 Modify the ``Course`` class as follows:
580 .. exercise:: Multiple many2many relations
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``.
588 Modify the ``Session`` class as follows:
592 .. exercise:: Views modification
594 For the *Course* model,
596 * the name and instructor for the course should be displayed in the tree
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
602 For the *Session* model,
604 * the name of the session and the session course should be displayed in
606 * the form view should display all the session's fields
608 Try to lay out the form views so that they're clear and readable.
620 Odoo provides two *inheritance* mechanisms to extend an existing model in a
623 The first inheritance mechanism allows a module to modify the behavior of a
624 model defined in another module:
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.
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.
636 .. image:: backend/inheritance_methods.png
641 * :attr:`~openerp.models.Model._inherit`
642 * :attr:`~openerp.models.Model._inherits`
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.
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:
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"/>
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
675 Operation to apply to the matched element:
678 appends ``xpath``'s body at the end of the matched element
680 replaces the matched element by the ``xpath``'s body
682 inserts the ``xpath``'s body as a sibling before the matched element
684 inserts the ``xpaths``'s body as a sibling after the matched element
686 alters the attributes of the matched element using special
687 ``attribute`` elements in the ``xpath``'s body
689 .. exercise:: Alter existing content
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
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
704 #. Create a file ``openacademy/partner.py`` and import it in
706 #. Create a file ``openacademy/views/partner.xml`` and add it to
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.
718 For instance, when used on the *Product* model the following domain selects
719 all *services* with a unit price over *1000*::
721 [('product_type', '=', 'service'), ('unit_price', '>', 1000)]
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"::
730 ('product_type', '=', 'service'),
732 ('unit_price', '>=', 1000),
733 ('unit_price', '<', 2000)]
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.
738 .. exercise:: Domains on relational fields
740 When selecting the instructor for a *Session*, only instructors (partners
741 with ``instructor`` set to ``True``) should be visible.
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
754 .. exercise:: More complex domains
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
762 #. Modify the *Session* model's domain
763 #. Modify ``openacademy/view/partner.xml`` to get access to
764 *Partner categories*:
768 Computed fields and default values
769 ==================================
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
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
781 .. danger:: ``self`` is a collection
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 +
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``.
793 .. code-block:: python
796 from openerp import models, fields
798 class ComputedModel(models.Model):
799 _name = 'test.computed'
801 name = fields.Char(compute='_compute_name')
803 def _compute_name(self):
805 record.name = str(random.randint(1, 1e6))
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::
812 def _compute_name(self):
813 self.name = str(random.randint(1, 1e6))
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::
824 from openerp import models, fields, api
826 class ComputedModel(models.Model):
827 _name = 'test.computed'
829 name = fields.Char(compute='_compute_name')
830 value = fields.Integer()
833 @api.depends('value')
834 def _compute_name(self):
835 self.name = "Record with value %s" % self.value
837 .. exercise:: Computed fields
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
845 #. Add a computed field to *Session*
846 #. Show the field in the *Session* view:
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::
857 name = fields.Char(default="Unknown")
858 user_id = fields.Many2one('res.users', default=lambda self: self.env.user)
860 .. exercise:: Active objects – Default values
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
873 Odoo has built-in rules making fields with an ``active`` field set
874 to ``False`` invisible.
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
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.
892 <!-- content of form view -->
893 <field name="amount"/>
894 <field name="unit_price"/>
895 <field name="price" readonly="1"/>
897 .. code-block:: python
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
907 'title': "Something bad happened",
908 'message': "It was very bad indeed",
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.
916 .. exercise:: Warning
918 Add an explicit onchange to warn about invalid values, like a negative
919 number of seats, or more participants than seats.
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>`.
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::
938 from openerp.exceptions import ValidationError
940 @api.constrains('age')
941 def _check_something(self):
944 raise ValidationError("Your record is too old: %s" % record.age)
945 # all records passed the test, don't return anything
947 .. exercise:: Add Python constraints
949 Add a constraint that checks that the instructor is not present in the
950 attendees of his/her own session.
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.
962 .. exercise:: Add SQL constraints
964 With the help of `PostgreSQL's documentation`_ , add the following
967 #. CHECK that the course description and the course title are different
968 #. Make the Course's name UNIQUE
974 .. exercise:: Exercise 6 - Add a duplicate option
976 Since we added a constraint for the Course name uniqueness, it is not
977 possible to use the "duplicate" function anymore (:menuselection:`Form -->
980 Re-implement your own "copy" method which allows to duplicate the Course
981 object, changing the original name into "Copy of [original name]".
993 Tree views can take supplementary attributes to further customize their
997 mappings of colors to conditions. If the condition evaluates to ``True``,
998 the corresponding color is applied to the row:
1002 <tree string="Idea Categories" colors="blue:state=='draft';red:state=='trashed'">
1003 <field name="name"/>
1004 <field name="state"/>
1007 Clauses are separated by ``;``, the color and condition are separated by
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.
1015 .. exercise:: List coloring
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
1023 Modify the session tree view:
1030 Displays records as calendar events. Their root element is ``<calendar>`` and
1031 their most common attributes are:
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.
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
1043 field (to define the label for each calendar event)
1047 <calendar string="Ideas" date_start="invent_date" color="inventor_id">
1048 <field name="name"/>
1051 .. exercise:: Calendar view
1053 Add a Calendar view to the *Session* model enabling the user to view the
1054 events associated to the Open Academy.
1058 #. Add an ``end_date`` field computed from ``start_date`` and
1061 .. tip:: the inverse function makes the field writable, and allows
1062 moving the sessions (via drag and drop) in the calendar view
1064 #. Add a calendar view to the *Session* model
1065 #. And add the calendar view to the *Session* model's actions
1072 Search view fields can take custom operators or :ref:`reference/orm/domains`
1073 for more flexible matching of results.
1075 Search views can also contain *filters* which act as toggles for predefined
1076 searches (defined using :ref:`reference/orm/domains`):
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"/>
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.
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).
1098 .. exercise:: Search views
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.
1110 Horizontal bar charts typically used to show project planning and advancement,
1111 their root element is ``<gantt>``.
1115 <gantt string="Ideas" date_start="invent_date" color="inventor_id">
1116 <level object="idea.idea" link="id" domain="[]">
1117 <field name="inventor_id"/>
1121 .. exercise:: Gantt charts
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.
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
1137 Graph views allow aggregated overview and analysis of models, their root
1138 element is ``<graph>``.
1140 Graph views have 4 display modes, the default mode is selected using the
1141 ``@type`` attribute.
1144 a multidimensional table, allows the selection of filers and dimensions
1145 to get the right aggregated dataset before moving to a more graphical
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.
1151 By default bars are side-by-side, they can be stacked by using
1152 ``@stacked="True"`` on the ``<graph>``
1154 2-dimensional line chart
1158 Graph views contain ``<field>`` with a mandatory ``@type`` attribute taking
1162 the field should be aggregated by default
1164 the field should be aggregated rather than grouped on
1168 <graph string="Total idea score by Inventor">
1169 <field name="inventor_id"/>
1170 <field name="score" type="measure"/>
1175 Graph views perform aggregations on database values, they do not work
1176 with non-stored computed fields.
1178 .. exercise:: Graph view
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.
1185 #. Add the number of attendees as a stored computed field
1186 #. Then add the relevant view
1193 Used to organize tasks, production processes, etc… their root element is
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.
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.
1202 Kanban views define the structure of each card as a mix of form elements
1203 (including basic HTML) and :ref:`reference/qweb`.
1205 .. exercise:: Kanban view
1207 Add a Kanban view that displays sessions grouped by course (columns are
1212 #. Add an integer ``color`` field to the *Session* model
1213 #. Add the kanban view and update the action
1220 Workflows are models associated to business objects describing their dynamics.
1221 Workflows are also used to track processes that evolve over time.
1223 .. exercise:: Almost a workflow
1225 Add a ``state`` field to the *Session* model. It will be used to define
1228 A sesion can have three possible states: Draft (default), Confirmed and
1231 In the session form, add a (read-only) field to
1232 visualize the state, and buttons to change it. The valid transitions are:
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
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.
1255 .. exercise:: Workflow
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
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
1274 In order to check if instances of the workflow are correctly
1275 created alongside sessions, go to :menuselection:`Settings -->
1276 Technical --> Workflows --> Instances`
1280 .. exercise:: Automatic transitions
1282 Automatically transition sessions from *Draft* to *Confirmed* when more
1283 than half the session's seats are reserved.
1289 .. exercise:: Server actions
1291 Replace the Python methods for synchronizing session state by
1294 Both the workflow and the server actions could have been created entirely
1304 Access control mechanisms must be configured to achieve a coherent security
1307 Group-based access control mechanisms
1308 -------------------------------------
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.
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``.
1326 .. code-block:: text
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
1332 .. exercise:: Add access control through the OpenERP interface
1334 Create a new user "John Smith". Then create a group
1335 "OpenAcademy / Session Read" with read access to the *Session* model.
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
1347 .. exercise:: Add access control through data files in your module
1351 * Create a group *OpenAcademy / Manager* with full access to all
1353 * Make *Session* and *Course* readable by all users
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
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.
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.
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>
1392 .. exercise:: Record rule
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.
1401 Create a new rule in ``openacademy/security/security.xml``:
1405 Internationalization
1406 ====================
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.
1419 .. tip:: The GNU gettext format (Portable Object) used by Odoo is
1420 integrated into LaunchPad, making it an online collaborative
1421 translation platform.
1423 .. code-block:: text
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
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")``)
1439 .. exercise:: Translate a module
1441 Choose a second language for your Odoo installation. Translate your
1442 module using the facilities provided by Odoo.
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
1464 #. Add ``from openerp import _`` to ``course.py`` and
1465 mark missing strings as translatable
1471 .. todo:: do we never reload translations?
1480 Odoo 8.0 comes with a new report engine based on :ref:`reference/qweb`,
1481 `Twitter Bootstrap`_ and Wkhtmltopdf_.
1483 A report is a combination two elements:
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,…)
1493 id="account_invoices"
1494 model="account.invoice"
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')"
1504 * A standard :ref:`QWeb view <reference/views/qweb>` for the actual report:
1508 <t t-call="report.html_container">
1509 <t t-foreach="docs" t-as="o">
1510 <t t-call="report.external_layout">
1512 <h2>Report title</h2>
1518 the standard rendering context provides a number of elements, the most
1522 the records for which the report is printed
1524 the user printing the report
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.
1533 .. exercise:: Create a report for the Session model
1535 For each session, it should display session's name, its start and end,
1536 and list the session's attendees.
1545 .. exercise:: Define a Dashboard
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
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
1560 .. note:: Available dashboard styles are ``1``, ``1-1``, ``1-2``,
1561 ``2-1`` and ``1-1-1``
1563 #. Update ``openacademy/__openerp__.py`` to reference the new data
1571 The web-service module offer a common interface for all web-services :
1576 Business objects can also be accessed via the distributed object
1577 mechanism. They can all be modified via the client interface with contextual
1580 Odoo is accessible through XML-RPC/JSON-RPC interfaces, for which libraries
1581 exist in many languages.
1586 The following example is a Python program that interacts with an Odoo
1587 server with the library xmlrpclib.
1593 root = 'http://%s:%d/xmlrpc/' % (HOST, PORT)
1595 uid = xmlrpclib.ServerProxy(root + 'common').login(db, username, password)
1596 print "Logged in as %s (uid: %d)" % (USER, uid)
1599 sock = xmlrpclib.ServerProxy(root + 'object')
1601 'name' : 'Another idea',
1602 'description' : 'This is another idea of mine',
1605 idea_id = sock.execute(db, uid, password, 'idea.idea', 'create', args)
1607 .. exercise:: Add a new service to the client
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.
1616 .. code-block:: python
1625 ROOT = 'http://%s:%d/xmlrpc/' % (HOST,PORT)
1628 uid = xmlrpclib.ServerProxy(ROOT + 'common').login(DB,USER,PASS)
1629 print "Logged in as %s (uid:%d)" % (USER,uid)
1631 call = functools.partial(
1632 xmlcprlib.ServerProxy(ROOT + 'object').execute,
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',
1645 Instead of using a hard-coded course id, the code can look up a course
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,
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.
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/
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.
1669 http://use-the-index-luke.com/sql/preface
1671 .. _POEdit: http://poedit.net
1673 .. _PostgreSQL's documentation:
1674 .. _table_constraint:
1675 http://www.postgresql.org/docs/9.3/static/ddl-constraints.html
1677 .. _python: http://python.org
1679 .. _XPath: http://w3.org/TR/xpath
1681 .. _twitter bootstrap: http://getbootstrap.com
1683 .. _wkhtmltopdf: http://wkhtmltopdf.org