summaryrefslogtreecommitdiff
path: root/doc/reference
diff options
context:
space:
mode:
Diffstat (limited to 'doc/reference')
-rw-r--r--doc/reference/guidelines.rst302
1 files changed, 189 insertions, 113 deletions
diff --git a/doc/reference/guidelines.rst b/doc/reference/guidelines.rst
index 5710bd36ff6..df8f0b5d4c2 100644
--- a/doc/reference/guidelines.rst
+++ b/doc/reference/guidelines.rst
@@ -32,7 +32,8 @@ Module structure
Directories
-----------
-A module is organised in important directories. Those contain the business logic; having a look at them should make you understand the purpose of the module.
+A module is organized in important directories. Those contain the business logic;
+having a look at them should make you understand the purpose of the module.
- *data/* : demo and data xml
- *models/* : models definition
@@ -49,108 +50,186 @@ Other optional directories compose the module.
File naming
-----------
-For *views* declarations, distinguish the backend views definition (list, form, kanban, ...), the templates (QWeb pages) and bundle (JS and CSS assets). Bundles are theorically QWeb templates, but should be in their own file :file:`assets.xml`.
-For *models*, split the business logic by sets of models, in each set
-select a main model, this model gives its name to the set. If there is
-only one model, its name is the same as the module name. For
-each set named <main_model> the following files may be created:
+File naming is important to quickly find information through all odoo addons.
+This section explains how to name files in a standard odoo module. As an
+example we use a plant nursery application. It holds two main models plant.nursery
+and plant.order.
-- :file:`models/{<main_model>}.py`
-- :file:`models/{<inherited_main_model>}.py`
-- :file:`views/{<main_model>}_templates.xml`
-- :file:`views/{<main_model>}_views.xml`
+Concerning *models*, split the business logic by sets of models belonging to
+a same main model. Each set lies in a given file named based on its main model.
+If there is only one model, its name is the same as the module name. Each
+inherited model should be in its own file to help understanding of impacted
+models.
-For instance, *sale* module introduces ``sale_order`` and
-``sale_order_line`` where ``sale_order`` is dominant. So the
-``<main_model>`` files will be named :file:`models/sale_order.py` and
-:file:`views/sale_order_views.py`.
+.. code-block:: text
-For *data*, split them by purpose : demo or data. The filename will be
-the main_model name, suffixed by *_demo.xml* or *_data.xml*.
+ addons/plant_nursery/
+ |-- models/
+ | |-- plant_nursery.py (first main model)
+ | |-- plant_order.py (another main model)
+ | |-- res_partner.py (inherited Odoo model)
-For *controllers*, the only file should be named *<my_module_name>.py*. If you need to inherit an existing controller from another module, its name will be *<module_name>.py*. Unlike *models*, each controller class should be contained in a separated file. For instance, *purchase* module implements its part of the customer portal in :file:`controllers/portal.py` and its own typical routes on :file:`controllers/purchase.py`.
+Concerning *security* and access rights and rules two main files should be used.
+First one is the definition of access rights done in a ``ir.model.access.csv``
+file. User groups are defined in ``<module>_groups.xml``. Access rules are
+defined in ``<model>_security.xml``.
-For *static files*, since the resources can be used in different contexts (frontend, backend, both), they will be included in only one bundle. So, CSS/Less, JavaScript and XML files should be suffixed with the name of the bundle type. i.e.: *im_chat_common.css*, *im_chat_common.js* for 'assets_common' bundle, and *im_chat_backend.css*, *im_chat_backend.js* for 'assets_backend' bundle.
-If the module owns only one file, the convention will be *<module_name>.ext* (i.e.: *project.js*).
-Don't link data (image, libraries) outside Odoo: do not use an
-URL to an image but copy it in our codebase instead.
+.. code-block:: text
-Regarding *data*, split them by purpose: data or demo. The filename will be
-the *main_model* name, suffixed by *_data.xml* or *_demo.xml*.
+ addons/plant_nursery/
+ |-- security/
+ | |-- ir.model.access.csv
+ | |-- plant_nusery_groups.xml
+ | |-- plant_nusery_security.xml
+ | |-- plant_order_security.xml
+
+Concerning *views*, backend views should be split like models and suffixed
+by ``_views.xml``. Backend views are list, form, kanban, activity, graph, pivot, ..
+views. To ease split by model in views main menus not linked to specific actions
+may be extracted into an optional ``<module>_menus.xml`` file. Templates (QWeb
+pages used notably for portal / website display) and bundles (import of JS and
+CSS assets) are put in separate files. Those are respectively
+``<model>_templates.xml`` and ``assets.xml`` files.
-Regarding *wizards*, naming convention is :
+.. code-block:: text
-- :file:`{<main_transient>}.py`
-- :file:`{<main_transient>}_views.xml`
+ addons/plant_nursery/
+ |-- views/
+ | | -- assets.xml (import of JS / CSS)
+ | | -- plant_nursery_menus.xml (optional definition of main menus)
+ | | -- plant_nursery_views.xml (backend views)
+ | | -- plant_nursery_templates.xml (portal templates)
+ | | -- plant_order_views.xml
+ | | -- plant_order_templates.xml
+ | | -- res_partner_views.xml
+
+Concerning *data*, split them by purpose (demo or data) and main model. Filenames
+will be the main_model name suffixed by ``_demo.xml`` or ``_data.xml``. For instance
+for an application having demo and data for its main model as well as subtypes,
+activities and mail templates all related to mail module:
-Where *<main_transient>* is the name of the dominant transient model, just like for *models*. <main_transient>.py can contains the models 'transient_model.action' and 'transient_model.action.line'.
+.. code-block:: text
+
+ addons/plant_nursery/
+ |-- data/
+ | |-- plant_nursery_data.xml
+ | |-- plant_nursery_demo.xml
+ | |-- mail_data.xml
-For *statistics reports*, their names should look like :
+Concerning *controllers*, generally all controllers belong to a single controller
+contained in a file named ``<module_name>.py``. An old convention in Odoo is to
+name this file ``main.py`` but it is considered as outdated. If you need to inherit
+an existing controller from another module do it in ``<inherited_module_name>.py``.
+For example adding portal controller in an application is done in ``portal.py``.
-- :file:`{<report_name_A>}_report.py`
-- :file:`{<report_name_A>}_report_views.py` (often pivot and graph views)
+.. code-block:: text
-For *printable reports*, you should have :
+ addons/plant_nursery/
+ |-- controllers/
+ | |-- plant_nursery.py
+ | |-- portal.py (inheriting portal/controllers/portal.py)
+ | |-- main.py (deprecated, replaced by plant_nursery.py)
+
+Concerning *static files*, Javascript files follow globally the same logic as
+python models. Each component should be in its own file with a meaningful name.
+For instance, the activity widgets are located in ``activity.js`` of mail module.
+Subdirectories can also be created to structure the 'package' (see web module
+for more details). The same logic should be applied for the templates of JS
+widgets (static XML files) and for their styles (scss files). Don't link
+data (image, libraries) outside Odoo: do not use an URL to an image but copy
+it in the codebase instead.
+
+Concerning *wizards*, naming convention is the same of for python models:
+``<transient>.py`` and ``<transient>_views.xml``. Both are put in the wizard
+directory. This naming comes from old odoo applications using the wizard
+keyword for transient models.
-- :file:`{<print_report_name>}_reports.py` (report actions, paperformat definition, ...)
-- :file:`{<print_report_name>}_templates.xml` (xml report templates)
+.. code-block:: text
+ addons/plant_nursery/
+ |-- wizard/
+ | |-- make_plant_order.py
+ | |-- make_plant_order_views.xml
-The complete tree should look like
+Concerning *statistics reports* done with python / SQL views and classic views
+naming is the following :
.. code-block:: text
- addons/<my_module_name>/
+ addons/plant_nursery/
+ |-- report/
+ | |-- plant_order_report.py
+ | |-- plant_order_report_views.xml
+
+Concerning *printable reports* which contain mainly data preparation and Qweb
+templates naming is the following :
+
+.. code-block:: text
+
+ addons/plant_nursery/
+ |-- report/
+ | |-- plant_order_reports.xml (report actions, paperformat, ...)
+ | |-- plant_order_templates.xml (xml report templates)
+
+The complete tree of our Odoo module therefore looks like
+
+.. code-block:: text
+
+ addons/plant_nursery/
|-- __init__.py
|-- __manifest__.py
|-- controllers/
| |-- __init__.py
- | |-- <inherited_module_name>.py
- | `-- <my_module_name>.py
+ | |-- plant_nursery.py
+ | |-- portal.py
|-- data/
- | |-- <main_model>_data.xml
- | `-- <inherited_main_model>_demo.xml
+ | |-- plant_nursery_data.xml
+ | |-- plant_nursery_demo.xml
+ | |-- mail_data.xml
|-- models/
| |-- __init__.py
- | |-- <main_model>.py
- | `-- <inherited_main_model>.py
+ | |-- plant_nursery.py
+ | |-- plant_order.py
+ | |-- res_partner.py
|-- report/
| |-- __init__.py
- | |-- <main_stat_report_model>.py
- | |-- <main_stat_report_model>_views.xml
- | |-- <main_print_report>_reports.xml
- | `-- <main_print_report>_templates.xml
+ | |-- plant_order_report.py
+ | |-- plant_order_report_views.xml
+ | |-- plant_order_reports.xml (report actions, paperformat, ...)
+ | |-- plant_order_templates.xml (xml report templates)
|-- security/
| |-- ir.model.access.csv
- | `-- <main_model>_security.xml
+ | |-- plant_nusery_groups.xml
+ | |-- plant_nusery_security.xml
+ | |-- plant_order_security.xml
|-- static/
| |-- img/
| | |-- my_little_kitten.png
- | | `-- troll.jpg
+ | | |-- troll.jpg
| |-- lib/
- | | `-- external_lib/
- | `-- src/
- | |-- js/
- | | |-- <my_module_name>.js
- `-- <my_widget_A>.js
- | |-- css/
- | | `-- <my_module_name>.css
- | |-- scss/
- | | `-- <my_module_name>.scss
- | `-- xml/
- | |-- <my_module_name>.xml
- `-- <my_widget_A>.xml
+ | | |-- external_lib/
+ | |-- src/
+ | | |-- js/
+ | | | |-- widget_a.js
+ | | | |-- widget_b.js
+ | | |-- scss/
+ | | | |-- widget_a.scss
+ | | | |-- widget_b.scss
+ | | |-- xml/
+ | | | |-- widget_a.xml
+ | | | |-- widget_a.xml
|-- views/
- | |-- <main_model>_templates.xml
- | |-- <main_model>_views.xml
- | |-- <inherited_main_model>_templates.xml
- | `-- <inherited_main_model>_views.xml
- `-- wizard/
- |-- <main_transient_A>.py
- |-- <main_transient_A>_views.xml
- |-- <main_transient_B>.py
- `-- <main_transient_B>_views.xml
+ | |-- assets.xml
+ | |-- plant_nursery_menus.xml
+ | |-- plant_nursery_views.xml
+ | |-- plant_nursery_templates.xml
+ | |-- plant_order_views.xml
+ | |-- plant_order_templates.xml
+ | |-- res_partner_views.xml
+ |-- wizard/
+ | |--make_plant_order.py
+ | |--make_plant_order_views.xml
.. note:: File names should only contain ``[a-z0-9_]`` (lowercase
alphanumerics and ``_``)
@@ -201,8 +280,8 @@ Odoo supports custom tags acting as syntactic sugar:
The 4 first tags are prefered over the *record* notation.
-Naming xml_id
--------------
+XML IDs and naming
+------------------
Security, View and Action
~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -214,9 +293,10 @@ Use the following pattern :
``kanban``, ``form``, ``tree``, ``search``, ...
* For an action: the main action respects :samp:`{<model_name>}_action`.
Others are suffixed with :samp:`_{<detail>}`, where *detail* is a
- lowercase string briefly explaining the action.
- This is used only if multiple actions are declared for the
- model.
+ lowercase string briefly explaining the action. This is used only if
+ multiple actions are declared for the model.
+* For window actions: suffix the action name by the specific view information
+ like :samp:`{<model_name>}_action_view_{<view_type}`.
* For a group: :samp:`{<model_name>}_group_{<group_name>}` where *group_name*
is the name of the group, generally 'user', 'manager', ...
* For a rule: :samp:`{<model_name>}_rule_{<concerned_group>}` where
@@ -224,17 +304,33 @@ Use the following pattern :
for the 'model_name_group_user', 'public' for public user, 'company'
for multi-company rules, ...).
+Name should be identical to xml id with dots replacing underscores. Actions
+should have a real naming as it is used as display name.
+
.. code-block:: xml
- <!-- views and menus -->
+ <!-- views -->
<record id="model_name_view_form" model="ir.ui.view">
+ <field name="name">model.name.view.form</field>
...
</record>
<record id="model_name_view_kanban" model="ir.ui.view">
+ <field name="name">model.name.view.kanban</field>
...
</record>
+ <!-- actions -->
+ <record id="model_name_action" model="ir.act.window">
+ <field name="name">Model Main Action</field>
+ ...
+ </record>
+
+ <record id="model_name_action_child_list" model="ir.actions.act_window">
+ <field name="name">Model Access Childs</field>
+ </record>
+
+ <!-- menus and sub-menus -->
<menuitem
id="model_name_menu_root"
name="Main Menu"
@@ -248,15 +344,6 @@ Use the following pattern :
sequence="10"
/>
- <!-- actions -->
- <record id="model_name_action" model="ir.actions.act_window">
- ...
- </record>
-
- <record id="model_name_action_child_list" model="ir.actions.act_window">
- ...
- </record>
-
<!-- security -->
<record id="module_name_group_user" model="res.groups">
...
@@ -270,30 +357,31 @@ Use the following pattern :
...
</record>
+Inheriting XML
+~~~~~~~~~~~~~~
+Xml Ids of inheriting views should use the same ID as the original record.
+It helps finding all inheritance at a glance. As final Xml Ids are prefixed
+by the module that creates them there is no overlap.
-.. note:: View names use dot notation ``my.model.view_type`` or
- ``my.model.view_type.inherit`` instead of *"This is the form view of
- My Model"*.
-
-
-Inherited XML
-~~~~~~~~~~~~~
-
-The naming pattern of inherited view is
-
-#. Extension mode: Use the same xml id than the original view you are extending, and suffix it by :samp:`{_inherit}` . For instance, the view :samp:`project.project_view_form` can be extended by :samp:`project_forecast.project_view_form_inherit`.
-#. Primary mode: Keep the original xml id.
-
+Naming should contain an ``.inherit.{details}`` suffix to ease understanding
+the override purpose when looking at its name.
.. code-block:: xml
- <record id="module2.model_view_form_inherit" model="ir.ui.view">
+ <record id="model_view_form" model="ir.ui.view">
+ <field name="name">model.view.form.inherit.module2</field>
<field name="inherit_id" ref="module1.model_view_form"/>
...
</record>
+New primary views do not require the inherit suffix as those are new records
+based upon the first one.
+
+.. code-block:: xml
+
<record id="module2.model_view_form" model="ir.ui.view">
+ <field name="name">model.view.form.module2</field>
<field name="inherit_id" ref="module1.model_view_form"/>
<field name="mode">primary</field>
...
@@ -311,11 +399,6 @@ source code tries to respect Python standard, but some of them can be ignored.
- E501: line too long
- E301: expected 1 blank line, found 0
- E302: expected 2 blank lines, found 1
-- E126: continuation line over-indented for hanging indent
-- E123: closing bracket does not match indentation of opening bracket's line
-- E127: continuation line over-indented for visual indent
-- E128: continuation line under-indented for visual indent
-- E265: block comment should start with '# '
Imports
-------
@@ -843,7 +926,7 @@ Symbols and Conventions
- Variable name :
- use camelcase for model variable
- use underscore lowercase notation for common variable.
- - prefix your variable name with *_id* or *_ids* if it contains a record id or list of id. Don't use ``partner_id`` to contain a record of res.partner
+ - suffix your variable name with *_id* or *_ids* if it contains a record id or list of id. Don't use ``partner_id`` to contain a record of res.partner
.. code-block:: python
@@ -964,17 +1047,10 @@ Javascript coding guidelines
- Use a linter (jshint, ...)
- Never add minified Javascript Libraries
- Use camelcase for class declaration
-- Unless your code is supposed to run on every page, target specific pages
- using the ``if_dom_contains`` function of website module. Target an
- element which is specific to the pages your code needs to run on
- using JQuery.
-
-.. code-block:: javascript
-
- odoo.website.if_dom_contains('.jquery_class_selector', function () {
- /*your code here*/
- });
+More precise JS guidelines are detailed at https://github.com/odoo/odoo/wiki/Javascript-coding-guidelines.
+You may also have a look at existing API in Javascript by looking Javascript
+References.
CSS coding guidelines
---------------------