For the to-do tasks to have a kanban board, we need Stages. Stages are board columns, and each task will fit into one of these columns:
todo_ui/__init__.py
to import the models
submodule:
from . import models
todo_ui/models
directory and add to it an __init__.py
file with this:
from . import todo_model
todo_ui/models/todo_model.py
Python code file:
# -*- coding: utf-8 -*- from odoo import models, fields, api class Tag(models.Model): _name = 'todo.task.tag' _description = 'To-do Tag' name = fields.Char('Name', 40, translate=True) class Stage(models.Model): _name = 'todo.task.stage' _description = 'To-do Stage' _order = 'sequence,name' name = fields.Char('Name', 40, translate=True) sequence = fields.Integer('Sequence')
Here we created the two new models that will be referenced in the to-do tasks.
Focusing on the task stages, we have a Python class, Stage
, based on the models.Model
class, which defines a new Odoo model called todo.task.stage
. We also have two fields: name
and sequence
. We can see some model attributes (prefixed with an underscore) that are new to us. Let's have a closer look at them.
Model classes can use additional attributes that control some of their behaviors. These are the most commonly used attributes:
_name
is the internal identifier for the Odoo model we are creating. Mandatory when creating a new model. _description
is a user friendly title for the model's records, shown when the model is viewed in the user interface. Optional but recommended._order
sets the default order to use when the model's records are browsed, or shown in a list view. It is a text string to be used as the SQL order by
clause, so it can be anything you could use there, although it has a smart behavior and supports translatable and many-to-one field names. For completeness, there are a couple of more attributes that can be used in advanced cases:
_rec_name
indicates the field to use as the record description when referenced from related fields, such as a many-to-one relationship. By default, it uses the name
field, which is a commonly found field in models. But this attribute allows us to use any other field for that purpose._table
is the name of the database table supporting the model. Usually, it is left to be calculated automatically, and is the model name with the dots replaced by underscores. But it's possible to set to indicate a specific table name.We can also have the _inherit
and _inherits
attributes, as explained in
Chapter 3
, Inheritance - Extending Existing Applications.
Odoo models are represented by Python classes. In the preceding code, we have a Python class Stage
, based on the models.Model
class, that defines a new Odoo model called todo.task.stage
.
Odoo models are kept in a central registry, also referred to as pool
in the older Odoo versions. It is a dictionary that keeps references to all the model classes available in the instance, and it can be referenced by a model name. Specifically, the code in a model method can use self.env['x']
to get a reference to a class representing the model x
.
You can see that model names are important since they are the keys used to access the registry. The convention for model names is to use a list of lowercase words joined with dots, such as todo.task.stage
. Other examples from the core modules are project.project
, project.task
, or project.task.type
. We should use the singular form todo.task
model instead of todo.tasks
. For historical reasons, it is possible to find some core models that don't follow this, such as res.users
, but it is not the rule.
Model names must be globally unique. Because of this, the first word should correspond to the main application the module relates to. In our example, it is todo
. Other examples from the core modules are project
, crm
, or sale
.
Python classes, on the other hand, are local to the Python file where they are declared. The identifier used for them is only significant for the code in that file. Because of this, class identifiers are not required to be prefixed by the main application they relate to. For example, there is no problem to name our class Stage
for the todo.task.stage
model. There is no risk of collision with possible classes with the same name on other modules.
Two different conventions for class identifiers can be used: snake_case
or CamelCase
. Historically, Odoo code used the snake case, and it is still possible to find classes that use this convention. But the trend is to use camel case, since it is the Python standard defined by the PEP8 coding conventions. You may have noticed that we are using the latter form.
In the preceding code and in the vast majority of Odoo models, classes are based on the models.Model
class. These type of models have permanent database persistence: database tables are created for them and their records are stored until explicitly deleted.
But Odoo also provides two other model types to be used: Transient and Abstract models.
models.TransientModel
class and are used for wizard-style user interaction. Their data is still stored in the database, but it is expected to be temporary. A vacuum job periodically clears old data from these tables. For example, the Load a Language dialog window, found in the Settings | Translations menu, uses a Transient model to store user selections and implement wizard logic.models.AbstractModel
class and have no data storage attached to them. They act as reusable feature sets to be mixed in with other models, using the Odoo inheritance capabilities. For example, mail.thread
is an Abstract model, provided by the Discuss
addon, used to add message and follower features to other models.The models and fields created through the Python classes have their metadata available through the user interface. In the Settings top menu, navigate to the Technical | Database Structure | Models menu item. Here, you will find the list of all the models available in the database. Clicking on a model in the list will open a form with its details:
This is a good tool to inspect the structure of a model since in one place, you can see the results of all the customizations from different modules. In this case, as you can see at the top-right corner in the In Apps field, the todo.task
definitions for this model come from both the todo_app
and todo_user
modules.
In the lower area, we have some information tabs available: a quick reference for the model's Fields, the Access Rights granted on security groups, and also list the Views available for this model.
We can find the model's External Identifier using, from the Developer menu, the View Metadata option. The model external identifiers, or XML IDs, are automatically generated by the ORM but fairly predictable: for the todo.task
model, the external identifier is model_todo_task
.