Odoo uses a client/server architecture in which clients are web browsers accessing the Odoo server via RPC. Both the server and client extensions are packaged as modules which are optionally loaded in a database.
Odoo modules can either add brand new business logic to an Odoo system or alter and extend existing business logic. Everything in Odoo starts and ends with modules.
In this article, we will cover the basics of creating Odoo Addon Modules. Recipes that we will cover in this.
Our main goal here is to understand how an addon module is structured and the typical incremental workflow to add components to it.
This post is an excerpt from the book Odoo 11 Development Cookbook - Second Edition by Alexandre Fayolle and Holger Brunn. With this book, you can create fast and efficient server-side applications using the latest features of Odoo v11.
For this article, you should have Odoo installed. You are also expected to be comfortable in discovering and installing extra addon modules.
In this recipe, we will create a new module, make it available in our Odoo instance, and install it.
We will need an Odoo instance ready to use.
For explanation purposes, we will assume Odoo is available at ~/odoo-dev/odoo, although any other location of your preference can be used.
We will also need a location for our Odoo modules. For the purpose of this recipe, we will use a local-addons directory alongside the odoo directory, at
~/odoo-dev/local-addons.
The following steps will create and install a new addon module:
$ cd ~/odoo-dev $ mkdir local-addons
$ mkdir local-addons/my_module
$ touch local-addons/my_module/__init__.py
{'name': 'My module'}
$ odoo/odoo-bin --addons-path=odoo/addon/,local-addons/
An Odoo module is a directory containing code files and other assets. The directory name used is the module's technical name. The name key in the module manifest is its title.
The __manifest__.py file is the module manifest. It contains a Python dictionary with information about the module, the modules it depends on, and the data files that it will load.
In the example, a minimal manifest file was used, but in real modules, we will want to add a few other important keys. These are discussed in the Completing the module manifest recipe, which we will see next.
The module directory must be Python-importable, so it also needs to have an __init__.py file, even if it's empty. To load a module, the Odoo server will import it. This will cause the code in the __init__.py file to be executed, so it works as an entry point to run the module Python code. Due to this, it will usually contain import statements to load the module Python files and submodules.
Known modules can be installed directly from the command line using the --init or
-i option. This list is initially set when you create a new database, from the modules found on the addons path provided at that time. It can be updated in an existing database with the Update Module List menu.
The manifest is an important piece for Odoo modules. It contains important information about the module and declares the data files that should be loaded.
We should have a module to work with, already containing a __manifest__.py manifest file. You may want to follow the previous recipe to provide such a module to work with.
We will add a manifest file and an icon to our addon module:
{ 'name': "Title", 'summary': "Short subtitle phrase", 'description': """Long description""", 'author': "Your name", 'license': "AGPL-3", 'website': "http://www.example.com", 'category': 'Uncategorized', 'version': '11.0.1.0.0', 'depends': ['base'], 'data': ['views.xml'], 'demo': ['demo.xml'], }
The remaining content is a regular Python dictionary, with keys and values. The example manifest we used contains the most relevant keys:
The image that is used as the module icon is the PNG file at static/description/icon.png.
Instead of having the long description in the module manifest, it's possible to have it in its own file. Since version 8.0, it can be replaced by a README file, with either a .txt, .rst, or an .md (Markdown) extension. Otherwise, include a description/index.html file in the module.
This HTML description will override a description defined in the manifest file.
There are a few more keys that are frequently used:
An addon module contains code files and other assets such as XML files and images. For most of these files, we are free to choose where to place them inside the module directory.
However, Odoo uses some conventions on the module structure, so it is advisable to follow them.
We are expected to have an addon module directory with only the __init__.py and __manifest__.py files. In this recipe, we suppose this is local-addons/my_module.
To create the basic skeleton for the addon module, perform the given steps:
$ cd local-addons/my_module $ mkdir models $ touch models/__init__.py $ mkdir controllers $ touch controllers/__init__.py $ mkdir views $ mkdir security $ mkdir data $ mkdir demo $ mkdir i18n $ mkdir -p static/description
from . import models from . import controllers
This should get us started with a structure containing the most used directories, similar to this one:
. ├── __init__.py ├── __manifest__.py │ ├── controllers │ └── __init__.py ├── data ├── demo ├── i18n ├── models │ └── __init__.py ├── security ├── static │ └── description └── views
To provide some context, an Odoo addon module can have three types of files:
The addon files are to be organized in these directories:
Models define the data structures to be used by our business applications. This recipe shows how to add a basic model to a module.
We will use a simple book library example to explain this; we want a model to represent books. Each book has a name and a list of authors.
We should have a module to work with. We will use an empty my_module for our explanation.
To add a new Model, we add a Python file describing it and then upgrade the addon module (or install it, if it was not already done). The paths used are relative to our addon module location (for example, ~/odoo-dev/local-addons/my_module/):
from odoo import models, fields class LibraryBook(models.Model): _name = 'library.book' name = fields.Char('Title', required=True) date_release = fields.Date('Release Date') author_ids = fields.Many2many( 'res.partner', string='Authors' )
from . import library_book
from . import models
odoo.modules.registry: module my_module: creating or updating database table
After this, the new library.book model should be available in our Odoo instance. If we have the technical tools activated, we can confirm that by looking it up at Settings | Technical | Database Structure | Models.
Our first step was to create a Python file where our new module was created.
Odoo models are objects derived from the Odoo Model Python class.
When a new model is defined, it is also added to a central model registry. This makes it easier for other modules to make modifications to it later.
Models have a few generic attributes prefixed with an underscore. The most important one is _name, providing a unique internal identifier to be used throughout the Odoo instance.
The model fields are defined as class attributes. We began defining the name field of the Char type. It is convenient for models to have this field, because by default, it is used as the record description when referenced from other models.
We also used an example of a relational field, author_ids. It defines a many-to-many relation between Library Books and the partners. A book can have many authors and each author can have written many books.
Next, we must make our module aware of this new Python file. This is done by the __init__.py files. Since we placed the code inside the models/ subdirectory, we need the previous __init__ file to import that directory, which should, in turn, contain another __init__ file importing each of the code files there (just one, in our case).
Changes to Odoo models are activated by upgrading the module. The Odoo server will handle the translation of the model class into database structure changes.
Although no example is provided here, business logic can also be added to these Python files, either by adding new methods to the Model's class or by extending the existing methods, such as create() or write().
Thus we learned about the structure of an Odoo addon module and learned, step-by-step, how to create a simple module from scratch.
To know more about, how to define access rules for your data; how to expose your data models to end users on the back end and on the front end; and how to create beautiful PDF versions of your data, read this book Odoo 11 Development Cookbook - Second Edition.
ERP tool in focus: Odoo 11
Building Your First Odoo Application
How to Scaffold a New module in Odoo 11