summaryrefslogtreecommitdiff
path: root/odoo/fields.py
diff options
context:
space:
mode:
Diffstat (limited to 'odoo/fields.py')
-rw-r--r--odoo/fields.py391
1 files changed, 151 insertions, 240 deletions
diff --git a/odoo/fields.py b/odoo/fields.py
index 70dadd84850..3ada0e914ab 100644
--- a/odoo/fields.py
+++ b/odoo/fields.py
@@ -99,169 +99,80 @@ class MetaField(type):
_global_seq = iter(itertools.count())
class Field(MetaField('DummyField', (object,), {})):
- """ The field descriptor contains the field definition, and manages accesses
- and assignments of the corresponding field on records. The following
- attributes may be provided when instanciating a field:
+ """The field descriptor contains the field definition, and manages accesses
+ and assignments of the corresponding field on records. The following
+ attributes may be provided when instanciating a field:
- :param string: the label of the field seen by users (string); if not
- set, the ORM takes the field name in the class (capitalized).
+ :param str string: the label of the field seen by users; if not
+ set, the ORM takes the field name in the class (capitalized).
- :param help: the tooltip of the field seen by users (string)
+ :param str help: the tooltip of the field seen by users
- :param readonly: whether the field is readonly (boolean, by default ``False``)
+ :param bool readonly: whether the field is readonly (default: ``False``)
- :param required: whether the value of the field is required (boolean, by
- default ``False``)
+ This only has an impact on the UI. Any field assignation in code will work
+ (if the field is a stored field or an inversable one).
- :param index: whether the field is indexed in database. Note: no effect
- on non-stored and virtual fields. (boolean, by default ``False``)
+ :param bool required: whether the value of the field is required (default: ``False``)
- :param default: the default value for the field; this is either a static
- value, or a function taking a recordset and returning a value; use
- ``default=None`` to discard default values for the field
+ :param bool index: whether the field is indexed in database. Note: no effect
+ on non-stored and virtual fields. (default: ``False``)
- :param states: 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
+ :param default: the default value for the field; this is either a static
+ value, or a function taking a recordset and returning a value; use
+ ``default=None`` to discard default values for the field
+ :type default: value or callable
+
+ :param dict states: a dictionary mapping state values to lists of UI attribute-value
+ pairs; possible attributes are: ``readonly``, ``required``, ``invisible``.
+
+ .. warning:: 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.
- :param groups: comma-separated list of group xml ids (string); this
- restricts the field access to the users of the given groups only
-
- :param bool copy: 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)
-
- .. _field-computed:
-
- .. rubric:: 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``.
-
- :param compute: name of a method that computes the field
-
- :param inverse: name of a method that inverses the field (optional)
-
- :param search: name of a method that implement search on the field (optional)
-
- :param store: whether the field is stored in database (boolean, by
- default ``False`` on computed fields)
-
- :param compute_sudo: whether the field should be computed in superuser
- mode to bypass access rights (boolean, defaults to ``True`` for
- stored fields and ``False`` for non-stored 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',
- inverse='_inverse_upper',
- search='_search_upper')
-
- @api.depends('name')
- def _compute_upper(self):
- for rec in self:
- rec.upper = rec.name.upper() if rec.name else False
-
- def _inverse_upper(self):
- for rec in self:
- rec.name = rec.upper.lower() if rec.upper else False
+ :param str groups: comma-separated list of group xml ids (string); this
+ restricts the field access to the users of the given groups only
- def _search_upper(self, operator, value):
- if operator == 'like':
- operator = 'ilike'
- return [('name', operator, value)]
+ :param bool company_dependent: whether the field value is dependent of the current company;
- The compute method has to assign the field on all records of the invoked
- recordset. The decorator :meth:`odoo.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; recomputation 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.
+ The value isn't stored on the model table. It is registered as `ir.property`.
+ When the value of the company_dependent field is needed, an `ir.property`
+ is searched, linked to the current company (and current record if one property
+ exists).
- 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.
+ If the value is changed on the record, it either modifies the existing property
+ for the current record (if one exists), or creates a new one for the current company
+ and res_id.
- 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.
+ If the value is changed on the company side, it will impact all records on which
+ the value hasn't been changed.
- 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``.
+ :param bool copy: 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)
- .. _field-related:
+ :param bool store: whether the field is stored in database
+ (default:``True``, ``False`` for computed fields)
- .. rubric:: Related fields
+ .. rubric:: Computed 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
+ :param str compute: name of a method that computes the field
- :param related: sequence of field names
+ .. seealso:: :ref:`Advanced Fields/Compute fields <reference/fields/compute>`
- Some field attributes are automatically copied from the source field if
- they are not redefined: ``string``, ``help``, ``readonly``, ``required`` (only
- if all fields in the sequence are required), ``groups``, ``digits``, ``size``,
- ``translate``, ``sanitize``, ``selection``, ``comodel_name``, ``domain``,
- ``context``. All semantic-free attributes are copied from the source
- field.
+ :param bool compute_sudo: whether the field should be recomputed as superuser
+ to bypass access rights (by default ``True`` for stored fields, ``False``
+ for non stored 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.
+ :param str inverse: name of a method that inverses the field (optional)
- .. _field-company-dependent:
+ :param str search: name of a method that implement search on the field (optional)
- .. rubric:: Company-dependent 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.
-
- .. warning::
-
- Company-dependent fields aren't stored in the table of the model they're defined on,
- instead, they are stored in the ``ir.property`` model's table.
-
- :param company_dependent: whether the field is company-dependent (boolean)
-
- .. _field-incremental-definition:
-
- .. rubric:: Incremental definition
-
- A field is defined as class attribute on a model class. If the model
- is extended (see :class:`~odoo.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
- subclasses.
-
- 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")
+ :param str related: sequence of field names
+ .. seealso:: :ref:`Advanced fields/Related fields <reference/fields/related>`
"""
type = None # type of the field (string)
@@ -1225,11 +1136,13 @@ class Integer(Field):
class Float(Field):
- """ The precision digits are given by the attribute
+ """The precision digits are given by the attribute
- :param digits: a pair (total, decimal), or a function taking a database
- cursor and returning a pair (total, decimal)
+ :param digits: a pair (total, decimal) or a
+ string referencing a `decimal.precision` record.
+ :type digits: tuple(int,int) or str
"""
+
type = 'float'
column_cast_from = ('int4', 'numeric', 'float8')
_slots = {
@@ -1290,8 +1203,8 @@ class Float(Field):
class Monetary(Field):
""" The decimal precision and currency symbol are taken from the attribute
- :param currency_field: name of the field holding the currency this monetary
- field is expressed in (default: `currency_id`)
+ :param str currency_field: name of the field holding the currency
+ this monetary field is expressed in (default: `\'currency_id\'`)
"""
type = 'monetary'
column_type = ('numeric', 'numeric')
@@ -1516,6 +1429,7 @@ class Char(_String):
may also be a callable such that ``translate(callback, value)``
translates ``value`` by using ``callback(term)`` to retrieve the
translation of terms.
+ :type translate: bool or callable
"""
type = 'char'
column_cast_from = ('text',)
@@ -1569,6 +1483,7 @@ class Text(_String):
may also be a callable such that ``translate(callback, value)``
translates ``value`` by using ``callback(term)`` to retrieve the
translation of terms.
+ :type translate: bool or callable
"""
type = 'text'
column_type = ('text', 'text')
@@ -1640,6 +1555,9 @@ class Html(_String):
class Date(Field):
+ """ This field type encapsulates a python date object.
+ :type date:
+ """
type = 'date'
column_type = ('date', 'date')
column_cast_from = ('timestamp',)
@@ -1651,17 +1569,18 @@ class Date(Field):
@staticmethod
def today(*args):
- """ Return the current day in the format expected by the ORM.
- This function may be used to compute default values.
+ """Return the current day in the format expected by the ORM.
+
+ .. note:: This function may be used to compute default values.
"""
return date.today()
@staticmethod
def context_today(record, timestamp=None):
- """
- Return the current date as seen in the client's timezone in a format
- fit for date fields. This method may be used to compute default
- values.
+ """Return the current date as seen in the client's timezone in a format
+ fit for date fields.
+
+ .. note:: This method may be used to compute default values.
:param record: recordset from which the timezone will be obtained.
:param datetime timestamp: optional datetime value to use instead of
@@ -1683,19 +1602,18 @@ class Date(Field):
@staticmethod
def to_date(value):
- """
- Attempt to convert ``value`` to a :class:`date` object.
+ """Attempt to convert ``value`` to a :class:`date` object.
+
+ .. warning::
- This function can take as input different kinds of types:
- * A falsy object, in which case None will be returned.
- * A string representing a date or datetime.
- * A date object, in which case the object will be returned as-is.
- * A datetime object, in which case it will be converted to a date object and all\
- datetime-specific information will be lost (HMS, TZ, ...).
+ If a datetime object is given as value,
+ it will be converted to a date object and all
+ datetime-specific information will be lost (HMS, TZ, ...).
:param value: value to convert.
+ :type value: str or date or datetime
:return: an object representing ``value``.
- :rtype: date
+ :rtype: date or None
"""
if not value:
return None
@@ -1738,6 +1656,9 @@ class Date(Field):
class Datetime(Field):
+ """ This field type encapsulates a python datetime object.
+ :type datetime:
+ """
type = 'datetime'
column_type = ('timestamp', 'timestamp')
column_cast_from = ('date',)
@@ -1749,33 +1670,32 @@ class Datetime(Field):
@staticmethod
def now(*args):
- """ Return the current day and time in the format expected by the ORM.
- This function may be used to compute default values.
+ """Return the current day and time in the format expected by the ORM.
+
+ .. note:: This function may be used to compute default values.
"""
# microseconds must be annihilated as they don't comply with the server datetime format
return datetime.now().replace(microsecond=0)
@staticmethod
def today(*args):
- """
- Return the current day, at midnight (00:00:00).
- """
+ """Return the current day, at midnight (00:00:00)."""
return Datetime.now().replace(hour=0, minute=0, second=0)
@staticmethod
def context_timestamp(record, timestamp):
- """
- Returns the given timestamp converted to the client's timezone.
- This method is *not* meant for use as a default initializer,
- because datetime fields are automatically converted upon
- display on client side. For default values, :meth:`fields.Datetime.now`
- should be used instead.
+ """Return the given timestamp converted to the client's timezone.
+
+ .. note:: This method is *not* meant for use as a default initializer,
+ because datetime fields are automatically converted upon
+ display on client side. For default values, :meth:`now`
+ should be used instead.
:param record: recordset from which the timezone will be obtained.
:param datetime timestamp: naive datetime value (expressed in UTC)
to be converted to the client timezone.
- :rtype: datetime
:return: timestamp converted to timezone-aware datetime in context timezone.
+ :rtype: datetime
"""
assert isinstance(timestamp, datetime), 'Datetime instance expected'
tz_name = record._context.get('tz') or record.env.user.tz
@@ -1792,18 +1712,12 @@ class Datetime(Field):
@staticmethod
def to_datetime(value):
- """
- Convert an ORM ``value`` into a :class:`datetime` value.
-
- This function can take as input different kinds of types:
- * A falsy object, in which case None will be returned.
- * A string representing a date or datetime.
- * A datetime object, in which case the object will be returned as-is.
- * A date object, in which case it will be converted to a datetime object.
+ """Convert an ORM ``value`` into a :class:`datetime` value.
:param value: value to convert.
+ :type value: str or date or datetime
:return: an object representing ``value``.
- :rtype: datetime
+ :rtype: datetime or None
"""
if not value:
return None
@@ -1823,12 +1737,13 @@ class Datetime(Field):
@staticmethod
def to_string(value):
- """
- Convert a :class:`datetime` or :class:`date` object to a string.
+ """Convert a :class:`datetime` or :class:`date` object to a string.
:param value: value to convert.
- :return: a string representing ``value`` in the server's datetime format, if ``value`` is
- of type :class:`date`, the time portion will be midnight (00:00:00).
+ :type value: datetime or date
+ :return: a string representing ``value`` in the server's datetime format,
+ if ``value`` is of type :class:`date`,
+ the time portion will be midnight (00:00:00).
:rtype: str
"""
return value.strftime(DATETIME_FORMAT) if value else False
@@ -2071,6 +1986,7 @@ class Selection(Field):
:param selection: specifies the possible values for this field.
It is given as either a list of pairs ``(value, label)``, or a model
method, or a method name.
+ :type selection: list(tuple(str,str)) or callable or str
:param selection_add: provides an extension of the selection in the case
of an overridden field. It is a list of pairs ``(value, label)`` or
@@ -2081,10 +1997,10 @@ class Selection(Field):
selection = [('a', 'A'), ('b', 'B')]
selection_add = [('c', 'C'), ('b',)]
> result = [('a', 'A'), ('c', 'C'), ('b', 'B')]
+ :type selection_add: list(tuple(str,str))
The attribute ``selection`` is mandatory except in the case of
- :ref:`related fields <field-related>` or :ref:`field extensions
- <field-incremental-definition>`.
+ ``related`` or extended fields.
"""
type = 'selection'
column_type = ('varchar', pg_varchar())
@@ -2181,7 +2097,7 @@ class Selection(Field):
return selection
def get_values(self, env):
- """ return a list of the possible values """
+ """Return a list of the possible values."""
selection = self.selection
if isinstance(selection, str):
selection = getattr(env[self.model_name], selection)()
@@ -2315,29 +2231,27 @@ class Many2one(_Relational):
""" The value of such a field is a recordset of size 0 (no
record) or 1 (a single record).
- :param comodel_name: name of the target model (string)
+ :param str comodel_name: name of the target model
+ ``Mandatory`` except for related or extended fields.
:param domain: an optional domain to set on candidate values on the
client side (domain or string)
- :param context: an optional context to use on the client side when
- handling that field (dictionary)
+ :param dict context: an optional context to use on the client side when
+ handling that field
- :param ondelete: what to do when the referred record is deleted;
+ :param str ondelete: what to do when the referred record is deleted;
possible values are: ``'set null'``, ``'restrict'``, ``'cascade'``
- :param auto_join: whether JOINs are generated upon search through that
- field (boolean, by default ``False``)
+ :param bool auto_join: whether JOINs are generated upon search through that
+ field (default: ``False``)
- :param delegate: set it to ``True`` to make fields of the target model
+ :param bool delegate: set it to ``True`` to make fields of the target model
accessible from the current model (corresponds to ``_inherits``)
:param check_company: add default domain ``['|', ('company_id', '=', False),
('company_id', '=', company_id)]``. Mark the field to be verified in
``_check_company``.
-
- The attribute ``comodel_name`` is mandatory except in the case of related
- fields or field extensions.
"""
type = 'many2one'
column_type = ('int4', 'int4')
@@ -2802,28 +2716,28 @@ class _RelationalMulti(_Relational):
class One2many(_RelationalMulti):
- """ One2many field; the value of such a field is the recordset of all the
- records in ``comodel_name`` such that the field ``inverse_name`` is equal to
- the current record.
+ """One2many field; the value of such a field is the recordset of all the
+ records in ``comodel_name`` such that the field ``inverse_name`` is equal to
+ the current record.
- :param comodel_name: name of the target model (string)
+ :param str comodel_name: name of the target model
- :param inverse_name: name of the inverse ``Many2one`` field in
- ``comodel_name`` (string)
+ :param str inverse_name: name of the inverse ``Many2one`` field in
+ ``comodel_name``
- :param domain: an optional domain to set on candidate values on the
- client side (domain or string)
+ :param domain: an optional domain to set on candidate values on the
+ client side (domain or string)
- :param context: an optional context to use on the client side when
- handling that field (dictionary)
+ :param dict context: an optional context to use on the client side when
+ handling that field
- :param auto_join: whether JOINs are generated upon search through that
- field (boolean, by default ``False``)
+ :param bool auto_join: whether JOINs are generated upon search through that
+ field (default: ``False``)
- :param limit: optional limit to use upon read (integer)
+ :param int limit: optional limit to use upon read
- The attributes ``comodel_name`` and ``inverse_name`` are mandatory except in
- the case of related fields or field extensions.
+ The attributes ``comodel_name`` and ``inverse_name`` are mandatory except in
+ the case of related fields or field extensions.
"""
type = 'one2many'
_slots = {
@@ -3065,46 +2979,43 @@ class One2many(_RelationalMulti):
class Many2many(_RelationalMulti):
""" Many2many field; the value of such a field is the recordset.
- :param comodel_name: name of the target model (string)
-
- The attribute ``comodel_name`` is mandatory except in the case of related
- fields or field extensions.
-
- :param relation: optional name of the table that stores the relation in
- the database (string)
+ :param comodel_name: name of the target model (string)
+ mandatory except in the case of related or extended fields
- :param column1: optional name of the column referring to "these" records
- in the table ``relation`` (string)
+ :param str relation: optional name of the table that stores the relation in
+ the database
- :param column2: optional name of the column referring to "those" records
- in the table ``relation`` (string)
+ :param str column1: optional name of the column referring to "these" records
+ in the table ``relation``
- The attributes ``relation``, ``column1`` and ``column2`` are optional.
- If not given, names are automatically generated from model names,
- provided ``model_name`` and ``comodel_name`` are different!
+ :param str column2: optional name of the column referring to "those" records
+ in the table ``relation``
- Note that having several fields with implicit relation parameters on a
- given model with the same comodel is not accepted by the ORM, since
- those field would use the same table. The ORM prevents two many2many
- fields to use the same relation parameters, except if
+ The attributes ``relation``, ``column1`` and ``column2`` are optional.
+ If not given, names are automatically generated from model names,
+ provided ``model_name`` and ``comodel_name`` are different!
- - both fields use the same model, comodel, and relation parameters are
- explicit; or
+ Note that having several fields with implicit relation parameters on a
+ given model with the same comodel is not accepted by the ORM, since
+ those field would use the same table. The ORM prevents two many2many
+ fields to use the same relation parameters, except if
- - at least one field belongs to a model with ``_auto = False``.
+ - both fields use the same model, comodel, and relation parameters are
+ explicit; or
- :param domain: an optional domain to set on candidate values on the
- client side (domain or string)
+ - at least one field belongs to a model with ``_auto = False``.
- :param context: an optional context to use on the client side when
- handling that field (dictionary)
+ :param domain: an optional domain to set on candidate values on the
+ client side (domain or string)
- :param limit: optional limit to use upon read (integer)
+ :param dict context: an optional context to use on the client side when
+ handling that field
- :param check_company: add default domain ``['|', ('company_id', '=', False),
- ('company_id', '=', company_id)]``. Mark the field to be verified in
- ``_check_company``.
+ :param check_company: add default domain ``['|', ('company_id', '=', False),
+ ('company_id', '=', company_id)]``. Mark the field to be verified in
+ ``_check_company``.
+ :param int limit: optional limit to use upon read
"""
type = 'many2many'
_slots = {