Sometimes, there is a particular feature that we want to be able to add to several different models. Repeating the same code in different files is bad programming practice, so it would be nice to be able to implement it once and be able to reuse it many times.
Abstract models allow us to just create a generic model that implements some feature that can then be inherited by regular models in order to make that feature available in them.
As an example, we will implement a simple Archive
feature. It adds the active
field to the model (if it doesn't exist already) and makes available an archive method to toggle the active
flag. This works because active
is a magic field; if present in a model by default, the records with active=False
will be filtered out from queries.
We will then add it to the Library Book model.
We will reuse the my_module
addon module from Chapter 3, Creating Odoo Modules.
The archive feature would certainly deserve its own addon module, or at least its own Python code file. But to keep the explanation as simple as possible, we will cram it into the models/library_book.py
file:
Library Book
model, where it will be used:class BaseArchive(models.AbstractModel): _name = 'base.archive' active = fields.Boolean(default=True) def do_archive(self): for record in self: record.active = not record.active
Library Book
model to inherit the Archive model:class LibraryBook(models.Model):
_name = 'library.book'
_inherit = ['base.archive']
# ...
An upgrade to the addon module is needed for the changes to be activated.
An Abstract model is created by a class based on
models.AbstractModel
instead of the usual models.Model
. It has all the attributes and capabilities of regular models; the difference is that the ORM will not create an actual representation for it in the database. So, it can have no data stored in it. It serves only as a template for a reusable feature that is to be added to regular models.
Our Archive abstract model is quite simple; it just adds the active
field and a method to toggle the value of the active
flag, which we expect to later be used via a button on the user interface.
When a model class is defined with the _inherit
attribute, it inherits the attribute methods of those classes, and what is defined in our class adds modifications to these inherited features.
The mechanism at play here is the same as that for a regular model extension (as per the Add features to a Model using inheritance recipe). You may have noticed that here, _inherit
uses a list of model identifiers instead of a string with one model identifier. In fact, _inherit
can have both forms. Using the list form allows us to inherit from multiple (usually Abstract) classes. In this case, we are inheriting just one, so a text string would be fine. A list was used instead to underline that a list can be used.
A noteworthy built-in abstract model is ir.needaction_mixin
. It allows for records to signal that a user action is needed on them and is widely used together with the Social Network messaging features.
Another widely used abstract model is mail.thread
, provided by the mail
(Discuss) addon module. It enables, on models, the message features that power the message wall seen at the bottom of many forms.
Other than AbstractModel
, a third model type is available: models.TransientModel
.
It has database representation like models.Model
, but the records created there are supposed to be temporary and regularly purged by a server-scheduled job. Other than that, Transient models work just like regular models.
They are useful for more complex user interactions known as wizards, for example, to request the user some input to then run a process or a report. In Chapter 6, Advanced Server Side Development Techniques, we explore how to use them for advanced user interaction.