Events¶
Events is an implementation of an Observer pattern for Odoo.
Components¶
Events¶
Events are a notification system.
On one side, one or many listeners await for an event to happen. On the other side, when such event happen, a notification is sent to the listeners.
An example of event is: ‘when a record has been created’.
The event system allows to write the notification code in only one place, in one Odoo addon, and to write as many listeners as we want, in different places, different addons.
We’ll see below how the on_record_create
is implemented.
Notifier¶
The first thing is to find where/when the notification should be sent.
For the creation of a record, it is in odoo.models.BaseModel.create()
.
We can inherit from the ‘base’ model to add this line:
class Base(models.AbstractModel):
_inherit = 'base'
@api.model
def create(self, vals):
record = super(Base, self).create(vals)
self._event('on_record_create').notify(record, fields=vals.keys())
return record
The models.base.Base._event()
method has been added to the ‘base’
model, so an event can be notified from any model. The
CollectedEvents.notify()
method triggers the event and forward the
arguments to the listeners.
This should be done only once. See models.base.Base
for a list of
events that are implemented in the ‘base’ model.
Listeners¶
Listeners are Components that respond to the event names.
The components must have a _usage
equals to 'event.listener'
, but it
doesn’t to be set manually if the component inherits from
'base.event.listener'
Here is how we would log something each time a record is created:
class MyEventListener(Component):
_name = 'my.event.listener'
_inherit = 'base.event.listener'
def on_record_create(self, record, fields=None):
_logger.info("%r has been created", record)
Many listeners such as this one could be added for the same event.
Collection and models¶
In the example above, the listeners is global. It will be executed for any
model and collection. You can also restrict a listener to only a collection or
model, using the _collection
or _apply_on
attributes.
class MyEventListener(Component):
_name = 'my.event.listener'
_inherit = 'base.event.listener'
_collection = 'magento.backend'
def on_record_create(self, record, fields=None):
_logger.info("%r has been created", record)
class MyModelEventListener(Component):
_name = 'my.event.listener'
_inherit = 'base.event.listener'
_apply_on = ['res.users']
def on_record_create(self, record, fields=None):
_logger.info("%r has been created", record)
If you want an event to be restricted to a collection, the notification must also precise the collection, otherwise all listeners will be executed:
collection = self.env['magento.backend']
self._event('on_foo_created', collection=collection).notify(record, vals)
An event can be skipped based on a condition evaluated from the notified
arguments. See skip_if()
-
odoo.addons.component_event.components.event.
skip_if
(cond)[source]¶ Decorator allowing to skip an event based on a condition
The condition is a python lambda expression, which takes the same arguments than the event.
Example:
@skip_if(lambda self, *args, **kwargs: self.env.context.get('connector_no_export')) def on_record_write(self, record, fields=None): _logger('I'll delay a job, but only if we didn't disabled ' ' the export with a context key') record.with_delay().export_record() @skip_if(lambda self, record, kind: kind == 'complete') def on_record_write(self, record, kind): _logger("I'll delay a job, but only if the kind is 'complete'") record.with_delay().export_record()
Odoo Models Extensions¶
Base Model¶
Extend the ‘base’ Odoo Model to add Events related features.
-
class
odoo.addons.component_event.models.base.
Base
[source]¶ Bases:
odoo.models.BaseModel
The base model, which is implicitly inherited by all models.
Add an
_event()
method to all Models. This method allows to trigger events.It also notifies the following events:
on_record_create(self, record, fields=None)
on_record_write(self, record, fields=none)
on_record_unlink(self, record)
on_record_unlink
is notified just before the unlink is done.