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: 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.