Monday, 22 September 2014

Odoo New API: Fields


Share it Please


A field is defined as class attribute on a model class.

Fields as descriptors:

In general, a descriptor is an object attribute with 'binding behavior', one whose attribute access has been overridden by methods in the descriptor protocol. Those methods are __get__(), __set__(), and __delete__(). If any of those methods are defined for an object, it is said to be a descriptor.

The field descriptor contains the field definition, and manages accesses and assignments of the corresponding field on records.

Descriptor methods:

1. def __get__(self, record, owner):

- Return the value of field 'self' on 'record'.

- Define behavior for when the descriptor's value is retrieved.

2. def __set__(self, record, value):

- Set the value of field 'self' on 'record'.

- Define behavior for when the descriptor's value is changed.

Fields Attributes:

The following attributes may be provided when instantiating a field:


The label of the field seen by users (string); if not set, the ORM takes the field name in the class (capitalized).


The tooltip of the field seen by users (string).


Whether the field is readonly (boolean, by default 'False').


Whether the value of the field is required (boolean, by default 'False').


Whether the field is indexed in database (boolean, by default 'False').


The default value for the field; this is either a static value, or a function taking a recordset and returning a value.

A dictionary mapping state values to lists of UI attribute-value pairs; possible attributes are: 'readonly', 'required', 'invisible'.

Note: Any state-based condition requires the 'state' field value to be available on the client-side UI. This is typically done by including it in the relevant views, possibly made invisible if not relevant for the end-user.


Comma-separated list of group xml ids (string); this restricts the field access to the users of the given groups only.

Whether the field value should be copied when the record is duplicated (default: 'True' for normal fields, 'False' for 'one2many' and computed fields, including property fields and related fields).

Computed fields:

One can define a field whose value is computed instead of simply being read from the database. The attributes that are specific to computed fields are given below. To define such a field, simply provide a value for the attribute 'compute':

- compute: name of a method that computes the field.
- inverse: name of a method that inverses the field (optional).
- search: name of a method that implement search on the field (optional).
- store: whether the field is stored in database (boolean, by default 'False' on computed fields).

The methods given for 'compute', 'inverse' and 'search' are model methods. Their signature is shown in the following example:

    upper = fields.Char(compute='_compute_upper',

    def _compute_upper(self):
        for rec in self:
            self.upper = if else False

    def _inverse_upper(self):
        for rec in self:
   = self.upper.lower() if self.upper else False

    def _search_upper(self, operator, value):
        if operator == 'like':
            operator = 'ilike'
        return [('name', operator, value)]

The compute method has to assign the field on all records of the invoked recordset. The decorator :meth:'openerp.api.depends' must be applied on the compute method to specify the field dependencies; those dependencies are used to determine when to recompute the field; re-computation is automatic and guarantees cache/database consistency. Note that the same method can be used for several fields, you simply have to assign all the given fields in the method; the method will be invoked once for all those fields.

By default, a computed field is not stored to the database, and is computed on-the-fly. Adding the attribute 'store=True' will store the field's values in the database. The advantage of a stored field is that searching on that field is done by the database itself. The disadvantage is that it requires database updates when the field must be recomputed.
The inverse method, as its name says, does the inverse of the compute method: the invoked records have a value for the field, and you must apply the necessary changes on the field dependencies such that the computation gives the expected value. Note that a computed field without an inverse method is readonly by default.
The search method is invoked when processing domains before doing an actual search on the model. It must return a domain equivalent to the condition: 'field operator value'.
Related fields:

The value of a related field is given by following a sequence of relational fields and reading a field on the reached model. The complete sequence of fields to traverse is specified by the attribute.

- related: sequence of field names.
The value of some attributes from related fields are automatically taken from the source field, when it makes sense. Examples are the attributes 'string' or 'selection' on selection fields.

By default, the values of related fields are not stored to the database. Add the attribute 'store=True' to make it stored, just like computed fields. Related fields are automatically recomputed when their dependencies are modified.
Company-dependent(property) fields:

Formerly known as 'property' fields, the value of those fields depends on the company. In other words, users that belong to different companies may see different values for the field on a given record.

- company_dependent: whether the field is company-dependent (boolean).
Incremental definition (Field Inheritance):

A field is defined as class attribute on a model class. If the model is extended (see :class:'~openerp.models.Model'), one can also extend the field definition by redefining a field with the same name and same type on the subclass. In that case, the attributes of the field are taken from the parent class and overridden by the ones given in sub-classes.

For instance, the second class below only adds a tooltip on the field 'state':

    class First(models.Model):
        _name = 'foo'
        state = fields.Selection([...], required=True)

    class Second(models.Model):
        _inherit = 'foo'
        state = fields.Selection(help="Blah blah blah")


Post a Comment