1 .. queue:: website/series
9 * This guide assumes `basic knowledge of Python
10 <http://docs.python.org/2/tutorial/>`_
11 * This guide assumes an installed Odoo
13 Creating a basic module
14 =======================
16 In Odoo, tasks are performed by creating modules.
18 Modules customize the behavior of an Odoo installation, either by adding new
19 behaviors or by altering existing ones (including behaviors added by other
22 First let's create a *module directory* which will contain a single module in
23 our case but may store multiple related (a project's) or not really related
24 (a company's) modules:
26 .. code-block:: console
30 then let's create the module's own directory:
32 .. code-block:: console
34 $ mkdir my-modules/academy
36 An Odoo module is a valid `Python package
37 <http://docs.python.org/2/tutorial/modules.html#packages>`_ so it needs an
38 empty ``__init__.py`` file.
40 Finally the mark of an Odoo module is the
41 :ref:`manifest file <reference/module/manifest>`, a Python dictionary describing
42 various module metadata.
46 A demonstration module
47 ======================
49 We have a "complete" module ready for installation.
51 Although it does absolutely nothing yet we can install it:
53 * start the Odoo server
55 .. code-block:: console
57 $ ./odoo.py --addons-path addons,my-modules
59 * go to http://localhost:8069
60 * create a new database including demonstration data
61 * to go :menuselection:`Settings --> Modules --> Installed Modules`
62 * in the top-right corner remove the *Installed* filter and search for
64 * click the :guilabel:`Install` button for the *Academy* module
68 * In a production development setting, modules should generally be created
69 using :ref:`Odoo's scaffolding <reference/cmdline/scaffold>` rather than by
75 :ref:`Controllers <reference/http/controllers>` interpret browser requests and
78 Add a simple controller and import it (so Odoo can find it):
82 Shut down your server (:kbd:`^C`) then restart it:
84 .. code-block:: console
86 $ ./odoo.py --addons-path addons,my-modules
88 and open a page to http://localhost:8069/academy/, you should see your "page"
91 .. figure:: website/helloworld.png
96 Generating HTML in Python isn't very pleasant.
98 The usual solution is templates_, pseudo-documents with placeholders and
99 display logic. Odoo allows any Python templating system, but provides its
100 own :ref:`QWeb <reference/qweb>` templating system which integrates with other
103 Let's create an XML file for our first template, register the template in the
104 manifest and alter the controller to use our template:
108 The templates iterates (``t-foreach``) on all the teachers (passed through the
109 *template context*), and prints each teacher in its own paragraph.
111 Finally restart Odoo and update the module's data (to install the template)
112 by going to :menuselection:`Settings --> Modules --> Installed Modules -->
113 Academy` and clicking :guilabel:`Upgrade`.
117 Alternatively, Odoo can be restarted :option:`and update modules at
118 the same time<odoo.py -u>`:
120 .. code-block:: console
122 $ odoo.py --addons-path addons,my-modules -d academy -u academy
124 Going to http://localhost:8069/academy/ should now result in:
126 .. image:: website/basic-list.png
131 :ref:`Odoo models <reference/orm/model>` map to database tables.
133 In the previous section we just displayed a list of string entered statically
134 in the Python code. This doesn't allow modifications and persistent storage
135 thereof, so we're now going to move our data to the database.
137 Defining the data model
138 -----------------------
140 First define an Odoo model file and import it:
144 Then setup :ref:`basic access control <reference/security/acl>` for the model
145 and and add them to the manifest:
149 this simply gives read access (``perm_read``) to all users (``group_id:id``
154 :ref:`Data files <reference/data>` (XML or CSV) have to be added to the
155 module manifest, Python files (models or controllers) don't but have to
156 be imported from ``__init__.py`` (directly or indirectly)
160 the administrator user bypasses access control, he has access to all
161 models even if not given access
166 The second step is to add some demonstration data to the system so it's
167 possible to test it easily. This is done by adding a ``demo``
168 :ref:`data file <reference/data>` to the manifest:
174 :ref:`Data files <reference/data>` can be used for demo and non-demo data.
175 Demo data are only loaded in "demonstration mode" and can be used for flow
176 testing and demonstration, non-demo data are always loaded and used as
177 initial system setup.
179 In this case we're using demonstration data because an actual user of the
180 system would want to input or import their own teachers list, this list
181 is only useful for testing.
186 The last step is to alter model and template to use our demonstration data:
188 #. fetch the records from the database instead of having a static list
189 #. Because :meth:`~openerp.models.Model.search` returns a set of records
190 matching the filter ("all records" here), alter the template to print each
195 Restart the server and update the module (in order to update the manifest
196 and templates and load the demo file) then navigate to
197 http://localhost:8069/academy/. The page should look little different: names
198 should simply be prefixed by a number (the database identifier for the
204 Odoo bundles a module dedicated to building websites.
206 So far we've used controllers fairly directly, but Odoo 8 added deeper
207 integration and a few other services (e.g. default styling, theming) via the
210 #. first, add ``website`` as a dependency to ``academy``
211 #. then add the ``website=True`` flag on the controller, this sets up a few
212 new variables on :ref:`the request object <reference/http/request>` and
213 allows using the website layout in our template
214 #. use the wesite layout in the template
218 After restarting the server while updating the module (in order to update the
219 manifest and template) access http://localhost:8069/academy/ should yield a
220 nicer looking page with branding and a number of built-in page elements
221 (top-level menu, footer, …)
223 .. image:: website/layout.png
225 The website layout also provides support for edition tools: click
226 :guilabel:`Sign In` (in the top-right), fill the credentials in (``admin`` /
227 ``admin`` by default) then click :guilabel:`Log In`.
229 You're now in Odoo "proper": the administrative interface. For now click on
230 the :guilabel:`Website` menu item (top-left corner.
232 We're back in the website but as an administrator, with access to advanced
233 edition features provided by the *website* support:
235 * a template code editor (:menuselection:`Customize --> HTML Editor`) where
236 you can see and edit all templates used for the current page
237 * the :guilabel:`Edit` button in the top-left switches to "edition mode" where
238 blocks (snippets) and rich text edition are available
239 * a number of other features such as mobile preview or :abbr:`SEO (Search
240 Engine Optimization)`
245 Controller methods are associated with *routes* via the
246 :func:`~openerp.http.route` decorator which takes a routing string and a
247 number of attributes to customise its behavior or security.
249 We've seen a "literal" routing string, which matches a URL section exactly,
250 but routing strings can also use `converter patterns`_ which match bits
251 of URLs and make those available as local variables. For instance we can
252 create a new controller method which takes a bit of URL and prints it out:
256 restart Odoo, access http://localhost:8069/academy/Alice/ and
257 http://localhost:8069/academy/Bob/ and see the difference.
259 As the name indicates, `converter patterns`_ don't just do extraction, they
260 also do *validation* and *conversion*, so we can change the new controller
261 to only accept integers:
265 Restart Odoo, access http://localhost:8069/academy/2, note how the old value
266 was a string, but the new one was converted to an integers. Try accessing
267 http://localhost:8069/academy/Carol/ and note that the page was not found:
268 since "Carol" is not an integer, the route was ignored and no route could be
271 Odoo provides an additional converter called ``model`` which provides records
272 directly when given their id, let's use that and create a generic page for
277 then change the list of model to link to our new controller:
281 Restart Odoo and upgrade the module, then you can visit each teacher's page.
282 As an exercise, try adding blocks to a teacher's page to write a biography,
283 then go to another teacher's page and so forth. You will discover, that your
284 biography is shared between all teachers, because blocks are added to the
285 *template*, and the *biography* template is shared between all teachers, when
286 one page is edited they're all edited at the same time.
291 Data which is specific to a record should be saved on that record, so let us
292 add a new biography field to our teachers:
296 Restart Odoo and update the views, reload the teacher's page and… the field
297 is invisible since it contains nothing.
299 .. todo:: the view has been set to noupdate because modified previously,
300 force via ``-i`` or do something else?
302 For record fields, templates can use a special ``t-field`` directive which
303 allows editing the field content from the website using field-specific
304 interfaces. Change the *person* template to use ``t-field``:
308 Restart Odoo and upgrade the module, there is now a placeholder under the
309 teacher's name and a new zone for blocks in :guilabel:`Edit` mode. Content
310 dropped there is stored in the correspoding teacher's ``biography`` field, and
311 thus specific to that teacher.
313 The teacher's name is also editable, and when saved the change is visible on
316 ``t-field`` can also take formatting options which depend on the exact field.
317 For instance if we display the modification date for a teacher's record:
321 it is displayed in a very "computery" manner and hard to read, but we could
322 ask for a human-readable version:
326 or a relative display:
330 Administration and ERP integration
331 ==================================
333 A brief and incomplete introduction to the Odoo administration
334 --------------------------------------------------------------
336 The Odoo administration was briefly seen during the `website support` section.
337 We can go back to it using :menuselection:`Administrator --> Administrator` in
338 the menu (or :guilabel:`Sign In` if you're signed out).
340 The conceptual structure of the Odoo backend is simple:
342 #. first are menus, a tree (menus can have sub-menus) of records. Menus
343 without children map to…
344 #. actions. Actions have various types: links, reports, code which Odoo should
345 execute or data display. Data display actions are called *window actions*,
346 and tell Odoo to display a given *model* according to a set of views…
347 #. a view has a type, a the broad category to which it corresponds (a list,
348 a graph, a calendar) and an *architecture* which customises the way the
349 model is displayed inside the view.
351 Editing in the Odoo administration
352 ----------------------------------
354 By default, an Odoo model is essentially invisible to a user. To make it
355 visible it must be available through an action, which itself needs to be
356 reachable, generally through a menu.
358 Let's create a menu for our model:
362 then accessing http://localhost:8069/web/ in the top left should be a menu
363 :guilabel:`Academy`, which is selected by default, as it is the first menu,
364 and having opened a listing of teachers. From the listing it is possible to
365 :guilabel:`Create` new teacher records, and to switch to the "form" by-record
368 If there is no definition of how to present records (a
369 :ref:`view <reference/views>`) Odoo will automatically create a basic one
370 on-the-fly. In our case it works for the "list" view for now (only displays
371 the teacher's name) but in the "form" view the HTML ``biography`` field is
372 displayed side-by-side with the ``name`` field and not given enough space.
373 Let's define a custom form view to make viewing and editing teacher records
378 Relations between models
379 ------------------------
381 We have seen a pair of "basic" fields stored directly in the record. There are
382 :ref:`a number of basic fields <reference/orm/fields/basic>`. The second
383 broad categories of fields are :ref:`relational
384 <reference/orm/fields/relational>` and used to link records to one another
385 (within a model or across models).
387 For demonstration, let's create a *courses* model. Each course should have a
388 ``teacher`` field, linking to a single teacher record, but each teacher can
393 let's also add views so we can see and edit a course's teacher:
397 It should also be possible to create new courses directly from a teacher's
398 page, or to see all the courses a teacher gives, so add
399 :class:`the inverse relationship <openerp.fields.One2many` to the *teachers*
404 Discussions and notifications
405 -----------------------------
407 Odoo provides technical models, which don't fulfill business needs in and of
408 themselves but add capabilities to business objects without having to build
411 One of these is the *Chatter* system, part of Odoo's email and messaging
412 system, which can add notifications and discussion threads to any model.
413 The model simply has to :attr:`~openerp.models.Model._inherit`
414 ``mail.thread``, and add the ``message_ids`` field to its form view to display
415 the discussion thread. Discussion threads are per-record.
417 For our academy, it makes sense to allow discussing courses to handle e.g.
418 scheduling changes or discussions between teachers and assistants:
422 At the bottom of each course form, there is now a discussion thread and the
423 possibility for users of the system to leave messages and follow or unfollow
424 discussions linked to specific courses.
429 Odoo also provides business models which allow using or opting in business
430 needs more directly. For instance the ``website_sale`` module sets up an
431 e-commerce site based on the products in the Odoo system. We can easily make
432 course subscriptions sellable by making our courses specific kinds of
435 Rather than the previous classical inheritance, this means replacing our
436 *course* model by the *product* model, and extending products in-place (to
437 add anything we need to it).
439 First of all we need to add a dependency on ``website_sale`` so we get both
440 products (via ``sale``) and the ecommerce interface:
444 restart Odoo, update your module, there is now a :guilabel:`Shop` section in
445 the website, listing a number of pre-filled (via demonstration data) products.
447 The second step is to replace the *courses* model by ``product.template``,
448 and add a new category of product for courses:
452 With this installed, a few courses are now available in the :guilabel:`Shop`,
453 though they may have to be looked for.
457 * to extend a model in-place, it's :attr:`inherited
458 <openerp.models.Model._inherit>` without giving it a new
459 :attr:`~openerp.models.Model._name`
460 * ``product.template`` already uses the discussions system, so we
461 can remove it from our extension model
462 * we're creating our courses as *published* by default so they can be
463 seen without having to log in
465 Altering existing views
466 -----------------------
468 So far, we have briefly seen:
470 * the creation of new models
471 * the creation of new views
472 * the creation of new records
473 * the alteration of existing models
475 We're left with the alteration of existing records and the alteration of
476 existing views. We'll do both on the :guilabel:`Shop` pages.
478 View alteration is done by creating *extension* views, which are applied on
479 top of the original view and alter it. These alteration views can be added or
480 removed without modifying the original, making it easier to try things out and
483 Since our courses are free, there is no reason to display their price on the
484 shop page, so we're going to alter the view and hide the price if it's 0. The
485 first task is finding out which view displays the price, this can be done via
486 :menuselection:`Customize --> HTML Editor` which lets us read the various
487 templates involved in rendering a page. Going through a few of them, "Product
488 item" looks a likely culprit.
490 Altering view architectures is done in 3 steps:
493 #. Extend the view to modify by setting the new view's ``inherit_id`` to the
494 modified view's external id
495 #. In the architecture, use the ``xpath`` tag to select and alter elements
496 from the modified view
500 The second thing we will change is making the product categories sidebar
501 visible by default: :menuselection:`Customize --> Product Categories` lets
502 you toggle a tree of product categories (used to filter the main display) on
505 This is done via the ``customize_show`` and ``active`` fields of extension
506 templates: an extension template (such as the one we've just created) can be
507 *customize_show=True*. This choice will display the view in the :guilabel:`Customize`
508 menu with a check box, allowing administrators to activate or disable them
509 (and easily customize their website pages).
511 We simply need to modify the *Product Categories* record and set its default
516 With this, the *Product Categories* sidebar will automatically be enabled when
517 the *Academy* module is installed.
519 .. _templates: http://en.wikipedia.org/wiki/Web_template
522 http://www.postgresql.org
523 .. _converter pattern:
524 .. _converter patterns:
525 http://werkzeug.pocoo.org/docs/routing/#rule-format