Coding standards of any programming language gives a uniform appearance to the code written by any developer. It improves the readability, and maintainability of the code and also reduces the complexity within.
Let’s discuss some of the odoo coding standards, which has to be followed during the development of an Odoo App.
Structure of Module:
Odoo modules have a predefined structure. Have to keep different types of files in different directories. So an odoo module is structured into different directories.
1. controllers: contains the HTTP routes (python files).
2. data: Contains the model data (XML file).
2. demo: Contains the demo data for the module (load if only the ‘load demo data’ is checked ).
4. doc: Contains the module documentation.
5. I18n: Contains the Translations.
6. models: All model definitions and its functions. (python files)
7. report: All report related files (both xml and py files.)
8. security: contains files which define the permission for the users (csv file) and record rules.
9. static: contains the web assets for the module,also contains subfolders description,css/, js/, img/, lib/, …
10. tests: contains the Python tests files.
11. views: contains the views and template definitions.
12. wizard: wizard related and their views.
14. __init__.py: To import the python directories (models, controllers, reports, ..,)
15. __manifest__.py: Core file of a module.
All directories are not mandatory. It may include according to the purpose of the module. But to create a module the outer ‘__init__.py’ and ‘__manifest__.py’ files are mandatory. Even there are no python files that are associated with the module, have to place an empty outer ‘__init__.py’ file.
Now let’s discuss the file naming conventions in odoo, file naming is important to quickly find information about the files and their purpose.To understand all of these can take an example module ‘Food Processing’.
In the case of models, a module contains main models and inherited models.
1) models/ food_products.py // Main Models.
2) models/ production_centers.py
3) models/ res_partner.py // Inherited Models.
The files in the views directory can name according to their purposes
1) food_process_views.xml (all type of view definitions of the model.)
2) food_process_templates.xml (portal templates)
3) food_process_menus.xml (definition of menu items)
4) food_process_config_views.xml (definition of configuration view section.)
5) assets.xml (import of js/ css and their paths.)
In the case of controllers, all controller operations included in a single file is same as the name of the module.For example ‘food_process.py’, if need to extend any existing controller, then give the file name as the inherited module name.
In the case of Qweb reports, it can separate as report templates and others like report actions and paperformat.
1) reports/ food_process_reports.xml
2) reports/ food_process_templates.xml
In the security directory, two types of files can be placed. One is the definition of access rights of all models in the module,and it includes in a csv file named ir.model.access.csv. Different user groups are used in the module defined in the <module_name>_groups.xml file Eg: food_process_groups.xml. The access rules or record rules concern about a module is defined in <model>_security.xml
Concerning data, they can split by purpose (demo or data).File naming will be the <main_model>_demo.xml Eg: food_process_demo.xml and <main_model>_data.xml
__manifest__.py file is the core file of a module. All details are included in this file like a dictionary, like name, version, author, depends, data, qweb, license, etc. All the view files in the module should be given the ‘data’ key and all qweb views should be listed in the ‘qweb’ key.
When creating the manifest, try to avoid the empty keys.
When adding the version number to a module it should be like, Odoo major version (12.0,11.0,10.0,..,) followed by the module version numbers (1.0.0).
Example: 22.214.171.124.0 is the version of the first release of the module Food Processing in Version 12.
When declaring a view or record in XML, one has to consider a lot of conventions,
1. All view records should have the record notation (using <record>).
2. For name a menu use <model_name>_menu, and for a submenu use <model_name>_menu_do_stuff.
3. For name action, the main action represent as <model_name>_action. Other actions are suffixed with the details.
Example: food_process_action, food_process_acion_view_invoice
4. For a view, use the convention as <model_name>_view_<view_type>.
where view type is tree,form,kanban…,
5. For a group: <model_name>_group_<group_name> .
The group_name is the name of the group, like ‘user’, ‘manager’, ‘advisor’…
6. For name a rule it should be like <model_name>_rule_<group_name>.
All python files have a number of imports according to the use. One has to follow an order while using imports.
1. External libraries (one per line sorted and split in python stdlib)
2. Imports of odoo
3. Imports from Odoo modules (rarely, and only if necessary)
Odoo tries to keep the Python coding statndards.So utilizing a linter will help to show the syntax, semantic warnings and errors that we ignore usually.
For this purpose we can use the PEP8 linter.Python Enhancement Proposal (PEP) consists of a set of rules to format the python code. Use of any linters will increase the standard and readability of the code.
Configuring PEP8 In Pycharm
1. Install the PEP8 library using pip.
sudo pip install pep8
sudo pip install pycodestyle
2. In Pycharm Goto Settings >> Tools >> External Tools, and click the ‘+’ button to add the pep8 option.
3. Set the ‘Program Name’, ‘Parameters’, and ‘Working directory’ correctly. Can use the ‘Insert_macro’ option to fill these details.
Note: Use of pep8 may remove in future, so it would be better to use the pycodestyle library instead.
Models and Variable naming.
> When name an odoo model, use the singular form of the name
Example: food.order and food .partner, not name like food.orders or food.partners.
> When name a Python Class use the camelcase form.
Example: class FoodProcessCenter(models.Model)
> Use camelcase notation for model variables which contains an instance of a model.
> Use underscore lowercase notation for common variable.
> One2Many and Many2Many fields should always have _ids as suffix
> Many2One fields should have _id as suffix
Example: item_id, center_id
Order of Attributes in a model
> Private attributes
Example: _name, _description, _inherit, _order, _rec_name,..,)
> Default method and _default_get method
Example: the default method naming pattern is _default_<field_name>
> Field declarations
> Compute, inverse and search methods.
Example: the compute method naming pattern is _compute_<field_name>
the search method naming pattern is _search_<field_name>
> Selection method (methods used to return computed values for selection fields)
Example: the selection method naming pattern is _selection_<field_name>
> Constrains methods (@api.constrains) and onchange methods (@api.onchange)
Example: the onchange method pattern is _onchange_<field_name>
the constraint method pattern is _check_<constraint_name>
> CRUD methods (ORM overrides)
> Action methods
> At last other methods that needed in the model.
We can use number of built-in function to increase the performance of code.
Example: filtered(), mapped(), sorted(), ..,
Consider we have a large number of records in a model variable food items. If we need to get the details which have the food type as ‘Fruits’ from these large number of records, then we can use the filtered option very easily.
fooditems = fooditems.filtered(lambda item: item.type == 'fruits')
It can be done in a single line. Also if we look into another example if we need to sort the records based on the field ‘item_priority’, can use the sort function.
fooditems = sorted(fooditems, key=lambda x: x.item_priority)
There is also a lot of built-in functions that we can use simply like . search_read(), search_count(), ..,