ORM

Class structure

Business objects are declared as Python classes inheriting from the orm.Model class, which makes them part of the OpenObject Model, and magically persisted by the ORM layer. Predefined attributes are used in the Python class to specify a business object’s characteristics for the ORM.

orm.Model attributes for business objects

_name (required)
business object name, in dot-notation (in module namespace)
_columns (required)
dictionary {field names: object fields declarations}
_defaults

dictionary: {field names: default values}. A default value can be a function or a literal.

Example:

_defaults['name'] = lambda self, cr, uid, context: 'eggs'
_inherit
_name of the parent business object (for prototype inheritance)
_inherits
for multiple / instance inheritance mechanism: dictionary mapping the _name of the parent business objects to the names of the corresponding foreign key fields to use
_constraints
list of tuples defining the Python constraints, in the form (func_name, message, fields). (message may be callable)
_sql_constraints
list of tuples defining the SQL constraints, in the form (name, sql_def, message). (message may be callable)
_order
Name of the field used to sort the records in lists (default: ‘id’)
_auto
if True (default) the ORM will create the database table – set to False to create your own table/view within the init() method. (Rarely used)
_log_access
If True (default), 4 fields (create_uid, create_date, write_uid, write_date) will be used to log record-level operations, made accessible via orm’s perm_read() function. (Rarely used)
_rec_name
Alternative field to use as name, used by orm’s name_get() (default: ‘name’) (Rarely used)

Inheritance mechanisms

_images/inheritance.png

ORM Fields

Objects may contain 3 types of fields: simple, relational, and functional. Simple types are: integers, floats, booleans, strings, etc. Relational fields represent the relationships between objects: one2many, many2one and many2many field. Functional fields are calculated on-the-fly as Python functions, but value can be stored in the database (for example for filtering).

Common attributes supported by all fields

  • string:

    field label (required)

  • required:

    True if mandatory

  • readonly:

    True if not editable

  • help:

    help tooltip

  • context:

    dictionary with contextual parameters (for relational fields)

  • select:

    True to optimize for list filtering (with database index), to include in search views

  • change_default:

    True if field should be usable as condition for default values in clients

  • states:

    dynamic changes to this field’s common attributes based on the state field

Simple fields

boolean(...) integer(...) date(...) datetime(...) time(...):

Example:

{
    'active': fields.boolean('Active'),
    'priority': fields.integer('Priority'),
    'start_date': fields.date('Start Date')
}
char(string, size, translate=False, ...) text(string, translate=False, ...)
Text-based fields
  • translate: True if field values can be translated by users
  • size: maximum size for char fields
float (string, digits=None, ...)
Floating-point value with arbitrary precision and scale
  • digits: tuple (precision, scale). If digits is not provided, it’s a float, not a decimal type.
selection(values, string, ...)
Field allowing selection among a set of predefined values
  • values: list of values (key-label tuples) or function returning such a list (required)
binary(string, filters=None, ...)
Field for storing a file or binary content.
  • filters: optional filename filters

Example:

{
    'picture': fields.binary('Picture', filters='*.png,*.gif')
}
reference(string, selection, size, ...)
Field with dynamic relationship to any other object, associated with an assistant widget
  • selection: model _name of allowed objects types and corresponding label (same format as values for selection fields) (required)
  • size: size of text column used to store it (as text: ‘model_name,object_id’) (required)

Example:

{
    'contact': fields.reference('Contact', [
        ('res.partner', 'Partner'),
        ('res.partner.contact', 'Contact')
    ], size=None)
}

Relational fields

All relational fields support domain attribute:
optional restriction in the form of arguments for search (see search())
many2one(obj, ondelete=’set null’, ...)
Relationship towards a parent object (using a foreign key)
  • obj: _name of destination object (required)
  • ondelete: deletion handling, e.g. ‘set null’, ‘cascade’, see PostgreSQL documentation
one2many(obj, field_id, ...)
Virtual relationship towards multiple objects (inverse of many2one)
  • obj: _name of destination object (required)
  • field_id: field name of inverse many2one, i.e. corresponding foreign key (required)
many2many(obj, rel, field1, field2, ...)
Bidirectional multiple relationship between objects
  • obj: _name of destination object (required)
  • rel: relationship table to use (required)
  • field1: name of field in rel table storing the id of the current object (required)
  • field2: name of field in rel table storing the id of the target object (required)

Functional fields

function(fnct, arg=None, fnct_inv=None, fnct_inv_arg=None, type=’float’, fnct_search=None, obj=None, method=False, store=False, multi=False,...)
Functional field simulating a real field, computed rather than stored
  • fnct: function to compute the field value (required)
def fnct(self, cr, uid, ids, field_name, arg, context)
returns a dictionary { ids→values } with values of type type
  • fnct_inv: function used to write a value in the field instead
def fnct_inv(obj, cr, uid, id, name, value, fnct_inv_arg, context)
  • type: type of simulated field (any other type besides ‘function’)
  • fnct_search: function used to search on this field
def fnct_search(obj, cr, uid, obj, name, args)
returns a list of tuples arguments for search(), e.g. [(‘id’, ‘in’, [1, 3, 5])]
  • obj: model _name of simulated field if it is a relational field
  • store, multi: optimization mechanisms (see usage in Performance Section)
related(f1, f2, ..., type=’float’, ...)
Shortcut field equivalent to browsing chained fields
  • f1, f2, ...: chained fields to reach target (f1 required)
  • type: type of target field
property(obj, type=’float’, view_load=None, group_name=None, ...)
Dynamic attribute with specific access rights
  • obj: object (required)
  • type: type of equivalent field

Special / Reserved field names

A few field names are reserved for pre-defined behavior in OpenObject. Some of them are created automatically by the system, and in that case any field with that name will be ignored.

field name description
id unique system identifier for the object (created by ORM, do not add it)
name defines the value used by default to display the record in lists, etc. if missing, set _rec_name to specify another field to use for this purpose
active defines visibility: records with active set to False are hidden by default
sequence defines order and allows drag&drop reordering if included in list views
state defines life-cycle stages for the object, used for workflows
parent_id defines tree structure on records, and enables child_of operator
parent_left used in conjunction with _parent_store flag on object, allows faster access to tree structures (see also Performance Optimization section)
parent_right used in conjunction with _parent_store flag on object, allows faster access to tree structures (see also Performance Optimization section)
create_date date of creation
create_uid record creator
write_date last update date of the record
write_uid record last updater

create_date, create_uid, write_date, write_uid are disabled if _log_access flag is set to False

ORM Methods

Inheriting from the orm.Model class makes all the ORM methods available on business objects. These methods may be invoked on the self object within the Python class itself (see examples in the table below), or from outside the class by first obtaining an instance via the ORM pool system.

To obtain a model class from anywhere self.pool[‘model_name’] is used. It can be a good idea to assign it to a variable:

model_name_obj = self.pool['model_name']
Common parameters, used by multiple methods:
  • cr:

    database connection (cursor)

  • uid:

    id of user performing the operation

  • ids:

    list of record ids, or single integer when there is only one id

  • context:

    optional dictionary of contextual parameters, such as user language:

    {'lang': 'en_US', ... }
    
create(cr, uid, values, context=None)
Creates a new record with the specified value. Returns: id of the new record
  • values: dictionary of field values for the record

Example:

idea_id = self.create(cr, uid, {
    'name': 'Spam recipe',
    'description': 'spam & eggs',
    'inventor_id': 45
})
search(cr, uid, args, offset=0, limit=None, order=None, context=None, count=False)
Returns: list of ids of records matching the given criteria
  • args: list of tuples specifying search criteria
  • offset: optional number of records to skip
  • limit: optional max number of records to return
  • order: optional columns to sort by (default: self._order)
  • count: if True, returns only the number of records matching the criteria, not their ids

Search criteria is defined in polish notation

Operators:
=, !=, >, >=, <, <=, like, ilike, =like, =ilike, in, not in, child_of, parent_left, parent_right
Prefix operators:
‘&’ (default), ‘|’, ‘!’

Example. Fetch non-spam partner shops + partner 34:

ids = self.search(
    cr,
    uid,
    [ '|', ('partner_id', '!=', 34), '!', ('name', 'ilike', 'spam')],
    order='partner_id'
)
browse(cr, uid, ids, context=None)

Fetches records as objects, allowing to use dot-notation to browse fields and relations Returns: object or list of objects requested

Example:

idea = self.browse(cr, uid, 42)
print 'Idea description:', idea.description
print 'Inventor country code:', idea.inventor_id.address[0].country_id.code
for vote in idea.vote_ids:
    print 'Vote %2.2f' % vote.vote
read(cr, user, ids, fields=None, context=None)
Returns: list of dictionaries with requested field values
  • fields: optional list of field names to return (default: all fields)

 Example:

results = self.read(cr, uid, [42, 43], ['name', 'inventor_id'])
print 'Inventor:', results[0]['inventor_id']
write(cr, uid, ids, values, context=None)
Updates records with given ids with the given values. Returns: True
  • values: dictionary of field values to update

Example:

self.write(cr, uid, [42, 43], {
    'name': 'spam & eggs',
    'partner_id': 24
})
copy(cr, uid, ids, defaults, context=None)
Duplicates record with given id updating it with defaults values. Returns: True
  • defaults: dictionary of field values to change before saving the duplicated object

Example:

self.write(cr, uid, [42, 43], {
    'name': 'spam & eggs',
    'partner_id': 24
})
unlink(cr, uid, ids, context=None)

Deletes records with the given ids Returns: True

Example:

self.unlink(cr, uid, [42, 43])
default_get(cr, uid, fields, context=None)
Returns: a dictionary of the default values for fields (set on the object class, by the user preferences, or via the context)
  • fields: list of field names

Example:

defs = self.default_get(cr, uid, ['name', 'active'])
# active should be True by default
assert defs['active']
log(cr, uid, id, message, context, details=True)
Returns: id of the record created in res.log
  • message: message to write
  • context: if passed then context is stored in db

Example:

self.log(cr, uid, st.id, _('Statement %s is confirmed, journal items are created.') % (st_number,))
perm_read(cr, uid, ids, details=True)
Returns: a list of ownership dictionaries for each requested record
  • details: if True, *_uid fields are replaced with the name of the user
  • returned dictionaries contain: object id (id), creator user id (create_uid), creation date (create_date), updater user id (write_uid), update date (write_date)

Example:

perms = self.perm_read(cr, uid, [42, 43])
print 'creator:', perms[0].get('create_uid', 'n/a')
read_group(cr, uid, domain, fields, groupby, offset=0, limit=None, context=None)
Returns: list of dictionaries (one dictionary for each record) containing:
  • the values of fields grouped by the fields in groupby argument
  • __domain: list of tuples specifying the search criteria
  • __context: dictionary with argument like groupby
  • domain: list specifying search criteria [[‘field_name’, ‘operator’, ‘value’], ...]
  • fields: list of fields present in the list view specified on the object
  • groupby: list of fields on which to groupby the records
  • offset: optional number of records to skip
  • limit: optional max number of records to return
fields_get(cr, uid, fields=None, context=None)
Returns a dictionary of field dictionaries, each one describing a field of the business object
  • fields: list of field names

Example:

class idea(orm.Model):
    (...)
    _columns = {
        'name': fields.char('Name', size=64)
        (...)
    }
    def test_fields_get(self, cr, uid):
        assert(self.fields_get('name')['size'] == 64)
fields_view_get(cr, uid, view_id=None, view_type=’form’, context=None, toolbar=False)
Returns a dictionary describing the composition of the requested view (including inherited views and extensions)
  • view_id: id of the view or None
  • view_type: type of view to return if view_id is None (‘form’, ‘tree’, ...)
  • toolbar: True to include contextual actions

Example:

def test_fields_view_get(self, cr, uid):
    idea_obj = self.pool['idea.idea']
    form_view = idea_obj.fields_view_get(cr, uid)
name_get(cr, uid, ids, context=None)

Returns tuples with the text representation of requested objects for to-many relationships

Example:

# Ideas should be shown with invention date
def name_get(self, cr, uid, ids):
    res = []
    for r in self.read(cr, uid, ids['name', 'create_date']):
        res.append((r['id'], '{} ({})'.format(r['name'], year)))
    return res
name_search(cr, uid, name=’‘, args=None, operator=’ilike’, context=None, limit=80)
Returns list of object names matching the criteria, used to provide completion for to-many relationships. Equivalent of search() on name + name_get()
  • name: object name to search for
  • operator: operator for name criterion
  • args, limit: same as for search())

Example:

# Countries can be searched by code or name
def name_search(self, cr, uid, name='', args=[], operator='ilike', context={}, limit=80):
    ids = []
    if name and len(name) == 2:
        ids = self.search(cr, user, [('code', '=', name)] + args, limit=limit, context=context)
    if not ids:
        ids = self.search(cr, user, [('name', operator, name)] + args, limit=limit, context=context)
    return self.name_get(cr, uid, ids)
export_data(cr, uid, ids, fields, context=None)
Exports fields for selected objects, returning a dictionary with a datas matrix. Used when exporting data via client menu.
  • fields: list of field names
  • context may contain import_comp (default: False) to make exported data compatible with import_data() (may prevent exporting some fields)
import_data(cr, uid, fields, data, mode=’init’, current_module=’‘, noupdate=False, context=None, filename=None)
Imports given data in the given module used when exporting data via client menu
  • fields: list of field names
  • data: data to import (see export_data())
  • mode: ‘init’ or ‘update’ for record creation
  • current_module: module name
  • noupdate: flag for record creation
  • filename: optional file to store partial import state for recovery