0fae78d745fff0848054a57850772ae4a6811713
[odoo/odoo.git] / openerp / fields.py
1 # -*- coding: utf-8 -*-
2 ##############################################################################
3 #
4 #    OpenERP, Open Source Management Solution
5 #    Copyright (C) 2013-2014 OpenERP (<http://www.openerp.com>).
6 #
7 #    This program is free software: you can redistribute it and/or modify
8 #    it under the terms of the GNU Affero General Public License as
9 #    published by the Free Software Foundation, either version 3 of the
10 #    License, or (at your option) any later version.
11 #
12 #    This program is distributed in the hope that it will be useful,
13 #    but WITHOUT ANY WARRANTY; without even the implied warranty of
14 #    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 #    GNU Affero General Public License for more details.
16 #
17 #    You should have received a copy of the GNU Affero General Public License
18 #    along with this program.  If not, see <http://www.gnu.org/licenses/>.
19 #
20 ##############################################################################
21
22 """ High-level objects for fields. """
23
24 from copy import copy
25 from datetime import date, datetime
26 from functools import partial
27 from operator import attrgetter
28 import logging
29 import pytz
30 import xmlrpclib
31
32 from types import NoneType
33
34 from openerp.tools import float_round, ustr, html_sanitize
35 from openerp.tools import DEFAULT_SERVER_DATE_FORMAT as DATE_FORMAT
36 from openerp.tools import DEFAULT_SERVER_DATETIME_FORMAT as DATETIME_FORMAT
37
38 DATE_LENGTH = len(date.today().strftime(DATE_FORMAT))
39 DATETIME_LENGTH = len(datetime.now().strftime(DATETIME_FORMAT))
40
41 _logger = logging.getLogger(__name__)
42
43 class SpecialValue(object):
44     """ Encapsulates a value in the cache in place of a normal value. """
45     def __init__(self, value):
46         self.value = value
47     def get(self):
48         return self.value
49
50 class FailedValue(SpecialValue):
51     """ Special value that encapsulates an exception instead of a value. """
52     def __init__(self, exception):
53         self.exception = exception
54     def get(self):
55         raise self.exception
56
57 def _check_value(value):
58     """ Return `value`, or call its getter if `value` is a :class:`SpecialValue`. """
59     return value.get() if isinstance(value, SpecialValue) else value
60
61
62 def resolve_all_mro(cls, name, reverse=False):
63     """ Return the (successively overridden) values of attribute `name` in `cls`
64         in mro order, or inverse mro order if `reverse` is true.
65     """
66     klasses = reversed(cls.__mro__) if reverse else cls.__mro__
67     for klass in klasses:
68         if name in klass.__dict__:
69             yield klass.__dict__[name]
70
71
72 class MetaField(type):
73     """ Metaclass for field classes. """
74     by_type = {}
75
76     def __init__(cls, name, bases, attrs):
77         super(MetaField, cls).__init__(name, bases, attrs)
78         if cls.type:
79             cls.by_type[cls.type] = cls
80
81         # compute class attributes to avoid calling dir() on fields
82         cls.column_attrs = []
83         cls.related_attrs = []
84         cls.description_attrs = []
85         for attr in dir(cls):
86             if attr.startswith('_column_'):
87                 cls.column_attrs.append((attr[8:], attr))
88             elif attr.startswith('_related_'):
89                 cls.related_attrs.append((attr[9:], attr))
90             elif attr.startswith('_description_'):
91                 cls.description_attrs.append((attr[13:], attr))
92
93
94 class Field(object):
95     """ The field descriptor contains the field definition, and manages accesses
96         and assignments of the corresponding field on records. The following
97         attributes may be provided when instanciating a field:
98
99         :param string: the label of the field seen by users (string); if not
100             set, the ORM takes the field name in the class (capitalized).
101
102         :param help: the tooltip of the field seen by users (string)
103
104         :param readonly: whether the field is readonly (boolean, by default ``False``)
105
106         :param required: whether the value of the field is required (boolean, by
107             default ``False``)
108
109         :param index: whether the field is indexed in database (boolean, by
110             default ``False``)
111
112         :param default: the default value for the field; this is either a static
113             value, or a function taking a recordset and returning a value
114
115         :param states: a dictionary mapping state values to lists of UI attribute-value
116             pairs; possible attributes are: 'readonly', 'required', 'invisible'.
117             Note: Any state-based condition requires the ``state`` field value to be
118             available on the client-side UI. This is typically done by including it in
119             the relevant views, possibly made invisible if not relevant for the
120             end-user.
121
122         :param groups: comma-separated list of group xml ids (string); this
123             restricts the field access to the users of the given groups only
124
125         :param bool copy: whether the field value should be copied when the record
126             is duplicated (default: ``True`` for normal fields, ``False`` for
127             ``one2many`` and computed fields, including property fields and
128             related fields)
129
130         .. _field-computed:
131
132         .. rubric:: Computed fields
133
134         One can define a field whose value is computed instead of simply being
135         read from the database. The attributes that are specific to computed
136         fields are given below. To define such a field, simply provide a value
137         for the attribute `compute`.
138
139         :param compute: name of a method that computes the field
140
141         :param inverse: name of a method that inverses the field (optional)
142
143         :param search: name of a method that implement search on the field (optional)
144
145         :param store: whether the field is stored in database (boolean, by
146             default ``False`` on computed fields)
147
148         The methods given for `compute`, `inverse` and `search` are model
149         methods. Their signature is shown in the following example::
150
151             upper = fields.Char(compute='_compute_upper',
152                                 inverse='_inverse_upper',
153                                 search='_search_upper')
154
155             @api.depends('name')
156             def _compute_upper(self):
157                 for rec in self:
158                     self.upper = self.name.upper() if self.name else False
159
160             def _inverse_upper(self):
161                 for rec in self:
162                     self.name = self.upper.lower() if self.upper else False
163
164             def _search_upper(self, operator, value):
165                 if operator == 'like':
166                     operator = 'ilike'
167                 return [('name', operator, value)]
168
169         The compute method has to assign the field on all records of the invoked
170         recordset. The decorator :meth:`openerp.api.depends` must be applied on
171         the compute method to specify the field dependencies; those dependencies
172         are used to determine when to recompute the field; recomputation is
173         automatic and guarantees cache/database consistency. Note that the same
174         method can be used for several fields, you simply have to assign all the
175         given fields in the method; the method will be invoked once for all
176         those fields.
177
178         By default, a computed field is not stored to the database, and is
179         computed on-the-fly. Adding the attribute ``store=True`` will store the
180         field's values in the database. The advantage of a stored field is that
181         searching on that field is done by the database itself. The disadvantage
182         is that it requires database updates when the field must be recomputed.
183
184         The inverse method, as its name says, does the inverse of the compute
185         method: the invoked records have a value for the field, and you must
186         apply the necessary changes on the field dependencies such that the
187         computation gives the expected value. Note that a computed field without
188         an inverse method is readonly by default.
189
190         The search method is invoked when processing domains before doing an
191         actual search on the model. It must return a domain equivalent to the
192         condition: `field operator value`.
193
194         .. _field-related:
195
196         .. rubric:: Related fields
197
198         The value of a related field is given by following a sequence of
199         relational fields and reading a field on the reached model. The complete
200         sequence of fields to traverse is specified by the attribute
201
202         :param related: sequence of field names
203
204         The value of some attributes from related fields are automatically taken
205         from the source field, when it makes sense. Examples are the attributes
206         `string` or `selection` on selection fields.
207
208         By default, the values of related fields are not stored to the database.
209         Add the attribute ``store=True`` to make it stored, just like computed
210         fields. Related fields are automatically recomputed when their
211         dependencies are modified.
212
213         .. _field-company-dependent:
214
215         .. rubric:: Company-dependent fields
216
217         Formerly known as 'property' fields, the value of those fields depends
218         on the company. In other words, users that belong to different companies
219         may see different values for the field on a given record.
220
221         :param company_dependent: whether the field is company-dependent (boolean)
222
223         .. _field-incremental-definition:
224
225         .. rubric:: Incremental definition
226
227         A field is defined as class attribute on a model class. If the model
228         is extended (see :class:`~openerp.models.Model`), one can also extend
229         the field definition by redefining a field with the same name and same
230         type on the subclass. In that case, the attributes of the field are
231         taken from the parent class and overridden by the ones given in
232         subclasses.
233
234         For instance, the second class below only adds a tooltip on the field
235         ``state``::
236
237             class First(models.Model):
238                 _name = 'foo'
239                 state = fields.Selection([...], required=True)
240
241             class Second(models.Model):
242                 _inherit = 'foo'
243                 state = fields.Selection(help="Blah blah blah")
244
245     """
246     __metaclass__ = MetaField
247
248     _attrs = None               # dictionary with all field attributes
249     _free_attrs = None          # list of semantic-free attribute names
250
251     automatic = False           # whether the field is automatically created ("magic" field)
252     inherited = False           # whether the field is inherited (_inherits)
253     column = None               # the column interfaced by the field
254     setup_done = False          # whether the field has been set up
255
256     name = None                 # name of the field
257     type = None                 # type of the field (string)
258     relational = False          # whether the field is a relational one
259     model_name = None           # name of the model of this field
260     comodel_name = None         # name of the model of values (if relational)
261     inverse_fields = None       # list of inverse fields (objects)
262
263     store = True                # whether the field is stored in database
264     index = False               # whether the field is indexed in database
265     manual = False              # whether the field is a custom field
266     copyable = True             # whether the field is copied over by BaseModel.copy()
267     depends = ()                # collection of field dependencies
268     recursive = False           # whether self depends on itself
269     compute = None              # compute(recs) computes field on recs
270     inverse = None              # inverse(recs) inverses field on recs
271     search = None               # search(recs, operator, value) searches on self
272     related = None              # sequence of field names, for related fields
273     related_sudo = True         # whether related fields should be read as admin
274     company_dependent = False   # whether `self` is company-dependent (property field)
275     default = None              # default(recs) returns the default value
276
277     string = None               # field label
278     help = None                 # field tooltip
279     readonly = False
280     required = False
281     states = None
282     groups = False              # csv list of group xml ids
283     change_default = None       # whether the field may trigger a "user-onchange"
284     deprecated = None           # whether the field is ... deprecated
285
286     def __init__(self, string=None, **kwargs):
287         kwargs['string'] = string
288         self._attrs = {key: val for key, val in kwargs.iteritems() if val is not None}
289         self._free_attrs = []
290
291     def copy(self, **kwargs):
292         """ copy(item) -> test
293
294         make a copy of `self`, possibly modified with parameters `kwargs` """
295         field = copy(self)
296         field._attrs = {key: val for key, val in kwargs.iteritems() if val is not None}
297         field._free_attrs = list(self._free_attrs)
298         return field
299
300     def set_class_name(self, cls, name):
301         """ Assign the model class and field name of `self`. """
302         self.model_name = cls._name
303         self.name = name
304
305         # determine all inherited field attributes
306         attrs = {}
307         for field in resolve_all_mro(cls, name, reverse=True):
308             if isinstance(field, type(self)):
309                 attrs.update(field._attrs)
310             else:
311                 attrs.clear()
312         attrs.update(self._attrs)       # necessary in case self is not in cls
313
314         # initialize `self` with `attrs`
315         if attrs.get('compute'):
316             # by default, computed fields are not stored, not copied and readonly
317             attrs['store'] = attrs.get('store', False)
318             attrs['copy'] = attrs.get('copy', False)
319             attrs['readonly'] = attrs.get('readonly', not attrs.get('inverse'))
320         if attrs.get('related'):
321             # by default, related fields are not stored
322             attrs['store'] = attrs.get('store', False)
323         if 'copy' in attrs:
324             # attribute is copyable because there is also a copy() method
325             attrs['copyable'] = attrs.pop('copy')
326
327         for attr, value in attrs.iteritems():
328             if not hasattr(self, attr):
329                 self._free_attrs.append(attr)
330             setattr(self, attr, value)
331
332         if not self.string:
333             self.string = name.replace('_', ' ').capitalize()
334
335         # determine self.default and cls._defaults in a consistent way
336         self._determine_default(cls, name)
337
338         self.reset()
339
340     def _determine_default(self, cls, name):
341         """ Retrieve the default value for `self` in the hierarchy of `cls`, and
342             determine `self.default` and `cls._defaults` accordingly.
343         """
344         self.default = None
345
346         # traverse the class hierarchy upwards, and take the first field
347         # definition with a default or _defaults for self
348         for klass in cls.__mro__:
349             field = klass.__dict__.get(name, self)
350             if not isinstance(field, type(self)):
351                 return      # klass contains another value overridden by self
352
353             if 'default' in field._attrs:
354                 # take the default in field, and adapt it for cls._defaults
355                 value = field._attrs['default']
356                 if callable(value):
357                     self.default = value
358                     cls._defaults[name] = lambda model, cr, uid, context: \
359                         self.convert_to_write(value(model.browse(cr, uid, [], context)))
360                 else:
361                     self.default = lambda recs: value
362                     cls._defaults[name] = value
363                 return
364
365             defaults = klass.__dict__.get('_defaults') or {}
366             if name in defaults:
367                 # take the value from _defaults, and adapt it for self.default
368                 value = defaults[name]
369                 value_func = value if callable(value) else lambda *args: value
370                 self.default = lambda recs: self.convert_to_cache(
371                     value_func(recs._model, recs._cr, recs._uid, recs._context),
372                     recs, validate=False,
373                 )
374                 cls._defaults[name] = value
375                 return
376
377     def __str__(self):
378         return "%s.%s" % (self.model_name, self.name)
379
380     def __repr__(self):
381         return "%s.%s" % (self.model_name, self.name)
382
383     ############################################################################
384     #
385     # Field setup
386     #
387
388     def reset(self):
389         """ Prepare `self` for a new setup. """
390         self.setup_done = False
391         # self._triggers is a set of pairs (field, path) that represents the
392         # computed fields that depend on `self`. When `self` is modified, it
393         # invalidates the cache of each `field`, and registers the records to
394         # recompute based on `path`. See method `modified` below for details.
395         self._triggers = set()
396         self.inverse_fields = []
397
398     def setup(self, env):
399         """ Complete the setup of `self` (dependencies, recomputation triggers,
400             and other properties). This method is idempotent: it has no effect
401             if `self` has already been set up.
402         """
403         if not self.setup_done:
404             self.setup_done = True
405             self._setup(env)
406
407     def _setup(self, env):
408         """ Do the actual setup of `self`. """
409         if self.related:
410             self._setup_related(env)
411         else:
412             self._setup_regular(env)
413
414         # put invalidation/recomputation triggers on field dependencies
415         model = env[self.model_name]
416         for path in self.depends:
417             self._setup_dependency([], model, path.split('.'))
418
419         # put invalidation triggers on model dependencies
420         for dep_model_name, field_names in model._depends.iteritems():
421             dep_model = env[dep_model_name]
422             for field_name in field_names:
423                 field = dep_model._fields[field_name]
424                 field._triggers.add((self, None))
425
426     #
427     # Setup of related fields
428     #
429
430     def _setup_related(self, env):
431         """ Setup the attributes of a related field. """
432         # fix the type of self.related if necessary
433         if isinstance(self.related, basestring):
434             self.related = tuple(self.related.split('.'))
435
436         # determine the related field, and make sure it is set up
437         recs = env[self.model_name]
438         for name in self.related[:-1]:
439             recs = recs[name]
440         field = self.related_field = recs._fields[self.related[-1]]
441         field.setup(env)
442
443         # check type consistency
444         if self.type != field.type:
445             raise Warning("Type of related field %s is inconsistent with %s" % (self, field))
446
447         # determine dependencies, compute, inverse, and search
448         self.depends = ('.'.join(self.related),)
449         self.compute = self._compute_related
450         self.inverse = self._inverse_related
451         if field._description_searchable(env):
452             # allow searching on self only if the related field is searchable
453             self.search = self._search_related
454
455         # copy attributes from field to self (string, help, etc.)
456         for attr, prop in self.related_attrs:
457             if not getattr(self, attr):
458                 setattr(self, attr, getattr(field, prop))
459
460     def _compute_related(self, records):
461         """ Compute the related field `self` on `records`. """
462         # when related_sudo, bypass access rights checks when reading values
463         others = records.sudo() if self.related_sudo else records
464         for record, other in zip(records, others):
465             if not record.id:
466                 # draft record, do not switch to another environment
467                 other = record
468             # traverse the intermediate fields; follow the first record at each step
469             for name in self.related[:-1]:
470                 other = other[name][:1]
471             record[self.name] = other[self.related[-1]]
472
473     def _inverse_related(self, records):
474         """ Inverse the related field `self` on `records`. """
475         for record in records:
476             other = record
477             # traverse the intermediate fields, and keep at most one record
478             for name in self.related[:-1]:
479                 other = other[name][:1]
480             if other:
481                 other[self.related[-1]] = record[self.name]
482
483     def _search_related(self, records, operator, value):
484         """ Determine the domain to search on field `self`. """
485         return [('.'.join(self.related), operator, value)]
486
487     # properties used by _setup_related() to copy values from related field
488     _related_string = property(attrgetter('string'))
489     _related_help = property(attrgetter('help'))
490     _related_readonly = property(attrgetter('readonly'))
491     _related_groups = property(attrgetter('groups'))
492
493     #
494     # Setup of non-related fields
495     #
496
497     def _setup_regular(self, env):
498         """ Setup the attributes of a non-related field. """
499         recs = env[self.model_name]
500
501         def make_depends(deps):
502             return tuple(deps(recs) if callable(deps) else deps)
503
504         # convert compute into a callable and determine depends
505         if isinstance(self.compute, basestring):
506             # if the compute method has been overridden, concatenate all their _depends
507             self.depends = ()
508             for method in resolve_all_mro(type(recs), self.compute, reverse=True):
509                 self.depends += make_depends(getattr(method, '_depends', ()))
510             self.compute = getattr(type(recs), self.compute)
511         else:
512             self.depends = make_depends(getattr(self.compute, '_depends', ()))
513
514         # convert inverse and search into callables
515         if isinstance(self.inverse, basestring):
516             self.inverse = getattr(type(recs), self.inverse)
517         if isinstance(self.search, basestring):
518             self.search = getattr(type(recs), self.search)
519
520     def _setup_dependency(self, path0, model, path1):
521         """ Make `self` depend on `model`; `path0 + path1` is a dependency of
522             `self`, and `path0` is the sequence of field names from `self.model`
523             to `model`.
524         """
525         env = model.env
526         head, tail = path1[0], path1[1:]
527
528         if head == '*':
529             # special case: add triggers on all fields of model (except self)
530             fields = set(model._fields.itervalues()) - set([self])
531         else:
532             fields = [model._fields[head]]
533
534         for field in fields:
535             if field == self:
536                 _logger.debug("Field %s is recursively defined", self)
537                 self.recursive = True
538                 continue
539
540             field.setup(env)
541
542             #_logger.debug("Add trigger on %s to recompute %s", field, self)
543             field._triggers.add((self, '.'.join(path0 or ['id'])))
544
545             # add trigger on inverse fields, too
546             for invf in field.inverse_fields:
547                 #_logger.debug("Add trigger on %s to recompute %s", invf, self)
548                 invf._triggers.add((self, '.'.join(path0 + [head])))
549
550             # recursively traverse the dependency
551             if tail:
552                 comodel = env[field.comodel_name]
553                 self._setup_dependency(path0 + [head], comodel, tail)
554
555     @property
556     def dependents(self):
557         """ Return the computed fields that depend on `self`. """
558         return (field for field, path in self._triggers)
559
560     ############################################################################
561     #
562     # Field description
563     #
564
565     def get_description(self, env):
566         """ Return a dictionary that describes the field `self`. """
567         desc = {'type': self.type}
568         for attr, prop in self.description_attrs:
569             value = getattr(self, prop)
570             if callable(value):
571                 value = value(env)
572             if value is not None:
573                 desc[attr] = value
574
575         return desc
576
577     # properties used by get_description()
578
579     def _description_store(self, env):
580         if self.store:
581             # if the corresponding column is a function field, check the column
582             column = env[self.model_name]._columns.get(self.name)
583             return bool(getattr(column, 'store', True))
584         return False
585
586     def _description_searchable(self, env):
587         if self.store:
588             column = env[self.model_name]._columns.get(self.name)
589             return bool(getattr(column, 'store', True)) or \
590                    bool(getattr(column, '_fnct_search', False))
591         return bool(self.search)
592
593     def _description_sortable(self, env):
594         if self.store:
595             column = env[self.model_name]._columns.get(self.name)
596             return bool(getattr(column, 'store', True))
597         if self.inherited:
598             # self is sortable if the inherited field is itself sortable
599             return self.related_field._description_sortable(env)
600         return False
601
602     _description_manual = property(attrgetter('manual'))
603     _description_depends = property(attrgetter('depends'))
604     _description_related = property(attrgetter('related'))
605     _description_company_dependent = property(attrgetter('company_dependent'))
606     _description_readonly = property(attrgetter('readonly'))
607     _description_required = property(attrgetter('required'))
608     _description_states = property(attrgetter('states'))
609     _description_groups = property(attrgetter('groups'))
610     _description_change_default = property(attrgetter('change_default'))
611     _description_deprecated = property(attrgetter('deprecated'))
612
613     def _description_string(self, env):
614         if self.string and env.lang:
615             name = "%s,%s" % (self.model_name, self.name)
616             trans = env['ir.translation']._get_source(name, 'field', env.lang)
617             return trans or self.string
618         return self.string
619
620     def _description_help(self, env):
621         if self.help and env.lang:
622             name = "%s,%s" % (self.model_name, self.name)
623             trans = env['ir.translation']._get_source(name, 'help', env.lang)
624             return trans or self.help
625         return self.help
626
627     ############################################################################
628     #
629     # Conversion to column instance
630     #
631
632     def to_column(self):
633         """ return a low-level field object corresponding to `self` """
634         assert self.store
635
636         # some columns are registry-dependent, like float fields (digits);
637         # duplicate them to avoid sharing between registries
638         _logger.debug("Create fields._column for Field %s", self)
639         args = {}
640         for attr, prop in self.column_attrs:
641             args[attr] = getattr(self, prop)
642         for attr in self._free_attrs:
643             args[attr] = getattr(self, attr)
644
645         if self.company_dependent:
646             # company-dependent fields are mapped to former property fields
647             args['type'] = self.type
648             args['relation'] = self.comodel_name
649             return fields.property(**args)
650
651         if isinstance(self.column, fields.function):
652             # it is too tricky to recreate a function field, so for that case,
653             # we make a stupid (and possibly incorrect) copy of the column
654             return copy(self.column)
655
656         return getattr(fields, self.type)(**args)
657
658     # properties used by to_column() to create a column instance
659     _column_copy = property(attrgetter('copyable'))
660     _column_select = property(attrgetter('index'))
661     _column_manual = property(attrgetter('manual'))
662     _column_string = property(attrgetter('string'))
663     _column_help = property(attrgetter('help'))
664     _column_readonly = property(attrgetter('readonly'))
665     _column_required = property(attrgetter('required'))
666     _column_states = property(attrgetter('states'))
667     _column_groups = property(attrgetter('groups'))
668     _column_change_default = property(attrgetter('change_default'))
669     _column_deprecated = property(attrgetter('deprecated'))
670
671     ############################################################################
672     #
673     # Conversion of values
674     #
675
676     def null(self, env):
677         """ return the null value for this field in the given environment """
678         return False
679
680     def convert_to_cache(self, value, record, validate=True):
681         """ convert `value` to the cache level in `env`; `value` may come from
682             an assignment, or have the format of methods :meth:`BaseModel.read`
683             or :meth:`BaseModel.write`
684
685             :param record: the target record for the assignment, or an empty recordset
686
687             :param bool validate: when True, field-specific validation of
688                 `value` will be performed
689         """
690         return value
691
692     def convert_to_read(self, value, use_name_get=True):
693         """ convert `value` from the cache to a value as returned by method
694             :meth:`BaseModel.read`
695
696             :param bool use_name_get: when True, value's diplay name will
697                 be computed using :meth:`BaseModel.name_get`, if relevant
698                 for the field
699         """
700         return False if value is None else value
701
702     def convert_to_write(self, value, target=None, fnames=None):
703         """ convert `value` from the cache to a valid value for method
704             :meth:`BaseModel.write`.
705
706             :param target: optional, the record to be modified with this value
707             :param fnames: for relational fields only, an optional collection of
708                 field names to convert
709         """
710         return self.convert_to_read(value)
711
712     def convert_to_onchange(self, value):
713         """ convert `value` from the cache to a valid value for an onchange
714             method v7.
715         """
716         return self.convert_to_write(value)
717
718     def convert_to_export(self, value, env):
719         """ convert `value` from the cache to a valid value for export. The
720             parameter `env` is given for managing translations.
721         """
722         if env.context.get('export_raw_data'):
723             return value
724         return bool(value) and ustr(value)
725
726     def convert_to_display_name(self, value):
727         """ convert `value` from the cache to a suitable display name. """
728         return ustr(value)
729
730     ############################################################################
731     #
732     # Descriptor methods
733     #
734
735     def __get__(self, record, owner):
736         """ return the value of field `self` on `record` """
737         if record is None:
738             return self         # the field is accessed through the owner class
739
740         if not record:
741             # null record -> return the null value for this field
742             return self.null(record.env)
743
744         # only a single record may be accessed
745         record.ensure_one()
746
747         try:
748             return record._cache[self]
749         except KeyError:
750             pass
751
752         # cache miss, retrieve value
753         if record.id:
754             # normal record -> read or compute value for this field
755             self.determine_value(record)
756         else:
757             # new record -> compute default value for this field
758             record.add_default_value(self)
759
760         # the result should be in cache now
761         return record._cache[self]
762
763     def __set__(self, record, value):
764         """ set the value of field `self` on `record` """
765         env = record.env
766
767         # only a single record may be updated
768         record.ensure_one()
769
770         # adapt value to the cache level
771         value = self.convert_to_cache(value, record)
772
773         if env.in_draft or not record.id:
774             # determine dependent fields
775             spec = self.modified_draft(record)
776
777             # set value in cache, inverse field, and mark record as dirty
778             record._cache[self] = value
779             if env.in_onchange:
780                 for invf in self.inverse_fields:
781                     invf._update(value, record)
782                 record._dirty = True
783
784             # determine more dependent fields, and invalidate them
785             if self.relational:
786                 spec += self.modified_draft(record)
787             env.invalidate(spec)
788
789         else:
790             # simply write to the database, and update cache
791             record.write({self.name: self.convert_to_write(value)})
792             record._cache[self] = value
793
794     ############################################################################
795     #
796     # Computation of field values
797     #
798
799     def _compute_value(self, records):
800         """ Invoke the compute method on `records`. """
801         # mark the computed fields failed in cache, so that access before
802         # computation raises an exception
803         exc = Warning("Field %s is accessed before being computed." % self)
804         for field in self.computed_fields:
805             records._cache[field] = FailedValue(exc)
806             records.env.computed[field].update(records._ids)
807         self.compute(records)
808         for field in self.computed_fields:
809             records.env.computed[field].difference_update(records._ids)
810
811     def compute_value(self, records):
812         """ Invoke the compute method on `records`; the results are in cache. """
813         with records.env.do_in_draft():
814             try:
815                 self._compute_value(records)
816             except (AccessError, MissingError):
817                 # some record is forbidden or missing, retry record by record
818                 for record in records:
819                     try:
820                         self._compute_value(record)
821                     except Exception as exc:
822                         record._cache[self.name] = FailedValue(exc)
823
824     def determine_value(self, record):
825         """ Determine the value of `self` for `record`. """
826         env = record.env
827
828         if self.store and not (self.depends and env.in_draft):
829             # this is a stored field
830             if self.depends:
831                 # this is a stored computed field, check for recomputation
832                 recs = record._recompute_check(self)
833                 if recs:
834                     # recompute the value (only in cache)
835                     self.compute_value(recs)
836                     # HACK: if result is in the wrong cache, copy values
837                     if recs.env != env:
838                         for source, target in zip(recs, recs.with_env(env)):
839                             try:
840                                 values = target._convert_to_cache({
841                                     f.name: source[f.name] for f in self.computed_fields
842                                 }, validate=False)
843                             except MissingError as e:
844                                 values = FailedValue(e)
845                             target._cache.update(values)
846                     # the result is saved to database by BaseModel.recompute()
847                     return
848
849             # read the field from database
850             record._prefetch_field(self)
851
852         elif self.compute:
853             # this is either a non-stored computed field, or a stored computed
854             # field in draft mode
855             if self.recursive:
856                 self.compute_value(record)
857             else:
858                 recs = record._in_cache_without(self)
859                 self.compute_value(recs)
860
861         else:
862             # this is a non-stored non-computed field
863             record._cache[self] = self.null(env)
864
865     def determine_default(self, record):
866         """ determine the default value of field `self` on `record` """
867         if self.default:
868             value = self.default(record)
869             record._cache[self] = self.convert_to_cache(value, record)
870         elif self.compute:
871             self._compute_value(record)
872         else:
873             record._cache[self] = SpecialValue(self.null(record.env))
874
875     def determine_inverse(self, records):
876         """ Given the value of `self` on `records`, inverse the computation. """
877         if self.inverse:
878             self.inverse(records)
879
880     def determine_domain(self, records, operator, value):
881         """ Return a domain representing a condition on `self`. """
882         if self.search:
883             return self.search(records, operator, value)
884         else:
885             return [(self.name, operator, value)]
886
887     ############################################################################
888     #
889     # Notification when fields are modified
890     #
891
892     def modified(self, records):
893         """ Notify that field `self` has been modified on `records`: prepare the
894             fields/records to recompute, and return a spec indicating what to
895             invalidate.
896         """
897         # invalidate the fields that depend on self, and prepare recomputation
898         spec = [(self, records._ids)]
899         for field, path in self._triggers:
900             if path and field.store:
901                 # don't move this line to function top, see log
902                 env = records.env(user=SUPERUSER_ID, context={'active_test': False})
903                 target = env[field.model_name].search([(path, 'in', records.ids)])
904                 if target:
905                     spec.append((field, target._ids))
906                     target.with_env(records.env)._recompute_todo(field)
907             else:
908                 spec.append((field, None))
909
910         return spec
911
912     def modified_draft(self, records):
913         """ Same as :meth:`modified`, but in draft mode. """
914         env = records.env
915
916         # invalidate the fields on the records in cache that depend on
917         # `records`, except fields currently being computed
918         spec = []
919         for field, path in self._triggers:
920             target = env[field.model_name]
921             computed = target.browse(env.computed[field])
922             if path == 'id':
923                 target = records - computed
924             elif path:
925                 target = (target.browse(env.cache[field]) - computed).filtered(
926                     lambda rec: rec._mapped_cache(path) & records
927                 )
928             else:
929                 target = target.browse(env.cache[field]) - computed
930
931             if target:
932                 spec.append((field, target._ids))
933
934         return spec
935
936
937 class Boolean(Field):
938     type = 'boolean'
939
940     def convert_to_cache(self, value, record, validate=True):
941         return bool(value)
942
943     def convert_to_export(self, value, env):
944         if env.context.get('export_raw_data'):
945             return value
946         return ustr(value)
947
948
949 class Integer(Field):
950     type = 'integer'
951
952     def convert_to_cache(self, value, record, validate=True):
953         if isinstance(value, dict):
954             # special case, when an integer field is used as inverse for a one2many
955             return value.get('id', False)
956         return int(value or 0)
957
958     def convert_to_read(self, value, use_name_get=True):
959         # Integer values greater than 2^31-1 are not supported in pure XMLRPC,
960         # so we have to pass them as floats :-(
961         if value and value > xmlrpclib.MAXINT:
962             return float(value)
963         return value
964
965     def _update(self, records, value):
966         # special case, when an integer field is used as inverse for a one2many
967         records._cache[self] = value.id or 0
968
969
970 class Float(Field):
971     """ The precision digits are given by the attribute
972
973     :param digits: a pair (total, decimal), or a function taking a database
974                    cursor and returning a pair (total, decimal)
975     """
976     type = 'float'
977     _digits = None              # digits argument passed to class initializer
978     digits = None               # digits as computed by setup()
979
980     def __init__(self, string=None, digits=None, **kwargs):
981         super(Float, self).__init__(string=string, _digits=digits, **kwargs)
982
983     def _setup_digits(self, env):
984         """ Setup the digits for `self` and its corresponding column """
985         self.digits = self._digits(env.cr) if callable(self._digits) else self._digits
986         if self.store:
987             column = env[self.model_name]._columns[self.name]
988             column.digits_change(env.cr)
989
990     def _setup_regular(self, env):
991         super(Float, self)._setup_regular(env)
992         self._setup_digits(env)
993
994     _related_digits = property(attrgetter('digits'))
995
996     _description_digits = property(attrgetter('digits'))
997
998     _column_digits = property(lambda self: not callable(self._digits) and self._digits)
999     _column_digits_compute = property(lambda self: callable(self._digits) and self._digits)
1000
1001     def convert_to_cache(self, value, record, validate=True):
1002         # apply rounding here, otherwise value in cache may be wrong!
1003         if self.digits:
1004             return float_round(float(value or 0.0), precision_digits=self.digits[1])
1005         else:
1006             return float(value or 0.0)
1007
1008
1009 class _String(Field):
1010     """ Abstract class for string fields. """
1011     translate = False
1012
1013     _column_translate = property(attrgetter('translate'))
1014     _related_translate = property(attrgetter('translate'))
1015     _description_translate = property(attrgetter('translate'))
1016
1017
1018 class Char(_String):
1019     """ Basic string field, can be length-limited, usually displayed as a
1020     single-line string in clients
1021
1022     :param int size: the maximum size of values stored for that field
1023     :param bool translate: whether the values of this field can be translated
1024     """
1025     type = 'char'
1026     size = None
1027
1028     _column_size = property(attrgetter('size'))
1029     _related_size = property(attrgetter('size'))
1030     _description_size = property(attrgetter('size'))
1031
1032     def convert_to_cache(self, value, record, validate=True):
1033         if value is None or value is False:
1034             return False
1035         return ustr(value)[:self.size]
1036
1037 class Text(_String):
1038     """ Text field. Very similar to :class:`~.Char` but used for longer
1039      contents and displayed as a multiline text box
1040
1041     :param translate: whether the value of this field can be translated
1042     """
1043     type = 'text'
1044
1045     def convert_to_cache(self, value, record, validate=True):
1046         if value is None or value is False:
1047             return False
1048         return ustr(value)
1049
1050 class Html(_String):
1051     type = 'html'
1052     sanitize = True                     # whether value must be sanitized
1053
1054     _column_sanitize = property(attrgetter('sanitize'))
1055     _related_sanitize = property(attrgetter('sanitize'))
1056     _description_sanitize = property(attrgetter('sanitize'))
1057
1058     def convert_to_cache(self, value, record, validate=True):
1059         if value is None or value is False:
1060             return False
1061         if validate and self.sanitize:
1062             return html_sanitize(value)
1063         return value
1064
1065
1066 class Date(Field):
1067     type = 'date'
1068
1069     @staticmethod
1070     def today(*args):
1071         """ Return the current day in the format expected by the ORM.
1072             This function may be used to compute default values.
1073         """
1074         return date.today().strftime(DATE_FORMAT)
1075
1076     @staticmethod
1077     def context_today(record, timestamp=None):
1078         """ Return the current date as seen in the client's timezone in a format
1079             fit for date fields. This method may be used to compute default
1080             values.
1081
1082             :param datetime timestamp: optional datetime value to use instead of
1083                 the current date and time (must be a datetime, regular dates
1084                 can't be converted between timezones.)
1085             :rtype: str
1086         """
1087         today = timestamp or datetime.now()
1088         context_today = None
1089         tz_name = record._context.get('tz') or record.env.user.tz
1090         if tz_name:
1091             try:
1092                 today_utc = pytz.timezone('UTC').localize(today, is_dst=False)  # UTC = no DST
1093                 context_today = today_utc.astimezone(pytz.timezone(tz_name))
1094             except Exception:
1095                 _logger.debug("failed to compute context/client-specific today date, using UTC value for `today`",
1096                               exc_info=True)
1097         return (context_today or today).strftime(DATE_FORMAT)
1098
1099     @staticmethod
1100     def from_string(value):
1101         """ Convert an ORM `value` into a :class:`date` value. """
1102         value = value[:DATE_LENGTH]
1103         return datetime.strptime(value, DATE_FORMAT).date()
1104
1105     @staticmethod
1106     def to_string(value):
1107         """ Convert a :class:`date` value into the format expected by the ORM. """
1108         return value.strftime(DATE_FORMAT)
1109
1110     def convert_to_cache(self, value, record, validate=True):
1111         if not value:
1112             return False
1113         if isinstance(value, basestring):
1114             if validate:
1115                 # force parsing for validation
1116                 self.from_string(value)
1117             return value[:DATE_LENGTH]
1118         return self.to_string(value)
1119
1120     def convert_to_export(self, value, env):
1121         if value and env.context.get('export_raw_data'):
1122             return self.from_string(value)
1123         return bool(value) and ustr(value)
1124
1125
1126 class Datetime(Field):
1127     type = 'datetime'
1128
1129     @staticmethod
1130     def now(*args):
1131         """ Return the current day and time in the format expected by the ORM.
1132             This function may be used to compute default values.
1133         """
1134         return datetime.now().strftime(DATETIME_FORMAT)
1135
1136     @staticmethod
1137     def context_timestamp(record, timestamp):
1138         """Returns the given timestamp converted to the client's timezone.
1139            This method is *not* meant for use as a _defaults initializer,
1140            because datetime fields are automatically converted upon
1141            display on client side. For _defaults you :meth:`fields.datetime.now`
1142            should be used instead.
1143
1144            :param datetime timestamp: naive datetime value (expressed in UTC)
1145                                       to be converted to the client timezone
1146            :rtype: datetime
1147            :return: timestamp converted to timezone-aware datetime in context
1148                     timezone
1149         """
1150         assert isinstance(timestamp, datetime), 'Datetime instance expected'
1151         tz_name = record._context.get('tz') or record.env.user.tz
1152         if tz_name:
1153             try:
1154                 utc = pytz.timezone('UTC')
1155                 context_tz = pytz.timezone(tz_name)
1156                 utc_timestamp = utc.localize(timestamp, is_dst=False)  # UTC = no DST
1157                 return utc_timestamp.astimezone(context_tz)
1158             except Exception:
1159                 _logger.debug("failed to compute context/client-specific timestamp, "
1160                               "using the UTC value",
1161                               exc_info=True)
1162         return timestamp
1163
1164     @staticmethod
1165     def from_string(value):
1166         """ Convert an ORM `value` into a :class:`datetime` value. """
1167         value = value[:DATETIME_LENGTH]
1168         if len(value) == DATE_LENGTH:
1169             value += " 00:00:00"
1170         return datetime.strptime(value, DATETIME_FORMAT)
1171
1172     @staticmethod
1173     def to_string(value):
1174         """ Convert a :class:`datetime` value into the format expected by the ORM. """
1175         return value.strftime(DATETIME_FORMAT)
1176
1177     def convert_to_cache(self, value, record, validate=True):
1178         if not value:
1179             return False
1180         if isinstance(value, basestring):
1181             if validate:
1182                 # force parsing for validation
1183                 self.from_string(value)
1184             value = value[:DATETIME_LENGTH]
1185             if len(value) == DATE_LENGTH:
1186                 value += " 00:00:00"
1187             return value
1188         return self.to_string(value)
1189
1190     def convert_to_export(self, value, env):
1191         if value and env.context.get('export_raw_data'):
1192             return self.from_string(value)
1193         return bool(value) and ustr(value)
1194
1195
1196 class Binary(Field):
1197     type = 'binary'
1198
1199
1200 class Selection(Field):
1201     """
1202     :param selection: specifies the possible values for this field.
1203         It is given as either a list of pairs (`value`, `string`), or a
1204         model method, or a method name.
1205     :param selection_add: provides an extension of the selection in the case
1206         of an overridden field. It is a list of pairs (`value`, `string`).
1207
1208     The attribute `selection` is mandatory except in the case of
1209     :ref:`related fields <field-related>` or :ref:`field extensions
1210     <field-incremental-definition>`.
1211     """
1212     type = 'selection'
1213     selection = None        # [(value, string), ...], function or method name
1214     selection_add = None    # [(value, string), ...]
1215
1216     def __init__(self, selection=None, string=None, **kwargs):
1217         if callable(selection):
1218             from openerp import api
1219             selection = api.expected(api.model, selection)
1220         super(Selection, self).__init__(selection=selection, string=string, **kwargs)
1221
1222     def _setup_related(self, env):
1223         super(Selection, self)._setup_related(env)
1224         # selection must be computed on related field
1225         field = self.related_field
1226         self.selection = lambda model: field._description_selection(model.env)
1227
1228     def set_class_name(self, cls, name):
1229         super(Selection, self).set_class_name(cls, name)
1230         # determine selection (applying 'selection_add' extensions)
1231         selection = None
1232         for field in resolve_all_mro(cls, name, reverse=True):
1233             if isinstance(field, type(self)):
1234                 # We cannot use field.selection or field.selection_add here
1235                 # because those attributes are overridden by `set_class_name`.
1236                 if 'selection' in field._attrs:
1237                     selection = field._attrs['selection']
1238                 if 'selection_add' in field._attrs:
1239                     selection = selection + field._attrs['selection_add']
1240             else:
1241                 selection = None
1242         self.selection = selection
1243
1244     def _description_selection(self, env):
1245         """ return the selection list (pairs (value, label)); labels are
1246             translated according to context language
1247         """
1248         selection = self.selection
1249         if isinstance(selection, basestring):
1250             return getattr(env[self.model_name], selection)()
1251         if callable(selection):
1252             return selection(env[self.model_name])
1253
1254         # translate selection labels
1255         if env.lang:
1256             name = "%s,%s" % (self.model_name, self.name)
1257             translate = partial(
1258                 env['ir.translation']._get_source, name, 'selection', env.lang)
1259             return [(value, translate(label)) for value, label in selection]
1260         else:
1261             return selection
1262
1263     @property
1264     def _column_selection(self):
1265         if isinstance(self.selection, basestring):
1266             method = self.selection
1267             return lambda self, *a, **kw: getattr(self, method)(*a, **kw)
1268         else:
1269             return self.selection
1270
1271     def get_values(self, env):
1272         """ return a list of the possible values """
1273         selection = self.selection
1274         if isinstance(selection, basestring):
1275             selection = getattr(env[self.model_name], selection)()
1276         elif callable(selection):
1277             selection = selection(env[self.model_name])
1278         return [value for value, _ in selection]
1279
1280     def convert_to_cache(self, value, record, validate=True):
1281         if not validate:
1282             return value or False
1283         if value in self.get_values(record.env):
1284             return value
1285         elif not value:
1286             return False
1287         raise ValueError("Wrong value for %s: %r" % (self, value))
1288
1289     def convert_to_export(self, value, env):
1290         if not isinstance(self.selection, list):
1291             # FIXME: this reproduces an existing buggy behavior!
1292             return value
1293         for item in self._description_selection(env):
1294             if item[0] == value:
1295                 return item[1]
1296         return False
1297
1298
1299 class Reference(Selection):
1300     type = 'reference'
1301     size = 128
1302
1303     def __init__(self, selection=None, string=None, **kwargs):
1304         super(Reference, self).__init__(selection=selection, string=string, **kwargs)
1305
1306     _related_size = property(attrgetter('size'))
1307
1308     _column_size = property(attrgetter('size'))
1309
1310     def convert_to_cache(self, value, record, validate=True):
1311         if isinstance(value, BaseModel):
1312             if ((not validate or value._name in self.get_values(record.env))
1313                     and len(value) <= 1):
1314                 return value.with_env(record.env) or False
1315         elif isinstance(value, basestring):
1316             res_model, res_id = value.split(',')
1317             return record.env[res_model].browse(int(res_id))
1318         elif not value:
1319             return False
1320         raise ValueError("Wrong value for %s: %r" % (self, value))
1321
1322     def convert_to_read(self, value, use_name_get=True):
1323         return "%s,%s" % (value._name, value.id) if value else False
1324
1325     def convert_to_export(self, value, env):
1326         return bool(value) and value.name_get()[0][1]
1327
1328     def convert_to_display_name(self, value):
1329         return ustr(value and value.display_name)
1330
1331
1332 class _Relational(Field):
1333     """ Abstract class for relational fields. """
1334     relational = True
1335     domain = None                       # domain for searching values
1336     context = None                      # context for searching values
1337
1338     _description_relation = property(attrgetter('comodel_name'))
1339     _description_context = property(attrgetter('context'))
1340
1341     def _description_domain(self, env):
1342         return self.domain(env[self.model_name]) if callable(self.domain) else self.domain
1343
1344     _column_obj = property(attrgetter('comodel_name'))
1345     _column_domain = property(attrgetter('domain'))
1346     _column_context = property(attrgetter('context'))
1347
1348     def null(self, env):
1349         return env[self.comodel_name]
1350
1351     def modified(self, records):
1352         # Invalidate cache for self.inverse_fields, too. Note that recomputation
1353         # of fields that depend on self.inverse_fields is already covered by the
1354         # triggers (see above).
1355         spec = super(_Relational, self).modified(records)
1356         for invf in self.inverse_fields:
1357             spec.append((invf, None))
1358         return spec
1359
1360
1361 class Many2one(_Relational):
1362     """ The value of such a field is a recordset of size 0 (no
1363     record) or 1 (a single record).
1364
1365     :param comodel_name: name of the target model (string)
1366
1367     :param domain: an optional domain to set on candidate values on the
1368         client side (domain or string)
1369
1370     :param context: an optional context to use on the client side when
1371         handling that field (dictionary)
1372
1373     :param ondelete: what to do when the referred record is deleted;
1374         possible values are: ``'set null'``, ``'restrict'``, ``'cascade'``
1375
1376     :param auto_join: whether JOINs are generated upon search through that
1377         field (boolean, by default ``False``)
1378
1379     :param delegate: set it to ``True`` to make fields of the target model
1380         accessible from the current model (corresponds to ``_inherits``)
1381
1382     The attribute `comodel_name` is mandatory except in the case of related
1383     fields or field extensions.
1384     """
1385     type = 'many2one'
1386     ondelete = 'set null'               # what to do when value is deleted
1387     auto_join = False                   # whether joins are generated upon search
1388     delegate = False                    # whether self implements delegation
1389
1390     def __init__(self, comodel_name=None, string=None, **kwargs):
1391         super(Many2one, self).__init__(comodel_name=comodel_name, string=string, **kwargs)
1392
1393     def set_class_name(self, cls, name):
1394         super(Many2one, self).set_class_name(cls, name)
1395         # determine self.delegate
1396         if not self.delegate:
1397             self.delegate = name in cls._inherits.values()
1398
1399     _column_ondelete = property(attrgetter('ondelete'))
1400     _column_auto_join = property(attrgetter('auto_join'))
1401
1402     def _update(self, records, value):
1403         """ Update the cached value of `self` for `records` with `value`. """
1404         records._cache[self] = value
1405
1406     def convert_to_cache(self, value, record, validate=True):
1407         if isinstance(value, (NoneType, int)):
1408             return record.env[self.comodel_name].browse(value)
1409         if isinstance(value, BaseModel):
1410             if value._name == self.comodel_name and len(value) <= 1:
1411                 return value.with_env(record.env)
1412             raise ValueError("Wrong value for %s: %r" % (self, value))
1413         elif isinstance(value, tuple):
1414             return record.env[self.comodel_name].browse(value[0])
1415         elif isinstance(value, dict):
1416             return record.env[self.comodel_name].new(value)
1417         else:
1418             return record.env[self.comodel_name].browse(value)
1419
1420     def convert_to_read(self, value, use_name_get=True):
1421         if use_name_get and value:
1422             # evaluate name_get() as superuser, because the visibility of a
1423             # many2one field value (id and name) depends on the current record's
1424             # access rights, and not the value's access rights.
1425             try:
1426                 return value.sudo().name_get()[0]
1427             except MissingError:
1428                 # Should not happen, unless the foreign key is missing.
1429                 return False
1430         else:
1431             return value.id
1432
1433     def convert_to_write(self, value, target=None, fnames=None):
1434         return value.id
1435
1436     def convert_to_onchange(self, value):
1437         return value.id
1438
1439     def convert_to_export(self, value, env):
1440         return bool(value) and value.name_get()[0][1]
1441
1442     def convert_to_display_name(self, value):
1443         return ustr(value.display_name)
1444
1445     def determine_default(self, record):
1446         super(Many2one, self).determine_default(record)
1447         if self.delegate:
1448             # special case: fields that implement inheritance between models
1449             value = record[self.name]
1450             if not value:
1451                 # the default value cannot be null, use a new record instead
1452                 record[self.name] = record.env[self.comodel_name].new()
1453
1454
1455 class UnionUpdate(SpecialValue):
1456     """ Placeholder for a value update; when this value is taken from the cache,
1457         it returns ``record[field.name] | value`` and stores it in the cache.
1458     """
1459     def __init__(self, field, record, value):
1460         self.args = (field, record, value)
1461
1462     def get(self):
1463         field, record, value = self.args
1464         # in order to read the current field's value, remove self from cache
1465         del record._cache[field]
1466         # read the current field's value, and update it in cache only
1467         record._cache[field] = new_value = record[field.name] | value
1468         return new_value
1469
1470
1471 class _RelationalMulti(_Relational):
1472     """ Abstract class for relational fields *2many. """
1473
1474     def _update(self, records, value):
1475         """ Update the cached value of `self` for `records` with `value`. """
1476         for record in records:
1477             if self in record._cache:
1478                 record._cache[self] = record[self.name] | value
1479             else:
1480                 record._cache[self] = UnionUpdate(self, record, value)
1481
1482     def convert_to_cache(self, value, record, validate=True):
1483         if isinstance(value, BaseModel):
1484             if value._name == self.comodel_name:
1485                 return value.with_env(record.env)
1486         elif isinstance(value, list):
1487             # value is a list of record ids or commands
1488             if not record.id:
1489                 record = record.browse()        # new record has no value
1490             result = record[self.name]
1491             # modify result with the commands;
1492             # beware to not introduce duplicates in result
1493             for command in value:
1494                 if isinstance(command, (tuple, list)):
1495                     if command[0] == 0:
1496                         result += result.new(command[2])
1497                     elif command[0] == 1:
1498                         result.browse(command[1]).update(command[2])
1499                         result += result.browse(command[1]) - result
1500                     elif command[0] == 2:
1501                         # note: the record will be deleted by write()
1502                         result -= result.browse(command[1])
1503                     elif command[0] == 3:
1504                         result -= result.browse(command[1])
1505                     elif command[0] == 4:
1506                         result += result.browse(command[1]) - result
1507                     elif command[0] == 5:
1508                         result = result.browse()
1509                     elif command[0] == 6:
1510                         result = result.browse(command[2])
1511                 elif isinstance(command, dict):
1512                     result += result.new(command)
1513                 else:
1514                     result += result.browse(command) - result
1515             return result
1516         elif not value:
1517             return self.null(record.env)
1518         raise ValueError("Wrong value for %s: %s" % (self, value))
1519
1520     def convert_to_read(self, value, use_name_get=True):
1521         return value.ids
1522
1523     def convert_to_write(self, value, target=None, fnames=None):
1524         # remove/delete former records
1525         if target is None:
1526             set_ids = []
1527             result = [(6, 0, set_ids)]
1528             add_existing = lambda id: set_ids.append(id)
1529         else:
1530             tag = 2 if self.type == 'one2many' else 3
1531             result = [(tag, record.id) for record in target[self.name] - value]
1532             add_existing = lambda id: result.append((4, id))
1533
1534         if fnames is None:
1535             # take all fields in cache, except the inverses of self
1536             fnames = set(value._fields) - set(MAGIC_COLUMNS)
1537             for invf in self.inverse_fields:
1538                 fnames.discard(invf.name)
1539
1540         # add new and existing records
1541         for record in value:
1542             if not record.id or record._dirty:
1543                 values = dict((k, v) for k, v in record._cache.iteritems() if k in fnames)
1544                 values = record._convert_to_write(values)
1545                 if not record.id:
1546                     result.append((0, 0, values))
1547                 else:
1548                     result.append((1, record.id, values))
1549             else:
1550                 add_existing(record.id)
1551
1552         return result
1553
1554     def convert_to_export(self, value, env):
1555         return bool(value) and ','.join(name for id, name in value.name_get())
1556
1557     def convert_to_display_name(self, value):
1558         raise NotImplementedError()
1559
1560     def _compute_related(self, records):
1561         """ Compute the related field `self` on `records`. """
1562         for record in records:
1563             value = record
1564             # traverse the intermediate fields, and keep at most one record
1565             for name in self.related[:-1]:
1566                 value = value[name][:1]
1567             record[self.name] = value[self.related[-1]]
1568
1569
1570 class One2many(_RelationalMulti):
1571     """ One2many field; the value of such a field is the recordset of all the
1572         records in `comodel_name` such that the field `inverse_name` is equal to
1573         the current record.
1574
1575         :param comodel_name: name of the target model (string)
1576
1577         :param inverse_name: name of the inverse `Many2one` field in
1578             `comodel_name` (string)
1579
1580         :param domain: an optional domain to set on candidate values on the
1581             client side (domain or string)
1582
1583         :param context: an optional context to use on the client side when
1584             handling that field (dictionary)
1585
1586         :param auto_join: whether JOINs are generated upon search through that
1587             field (boolean, by default ``False``)
1588
1589         :param limit: optional limit to use upon read (integer)
1590
1591         The attributes `comodel_name` and `inverse_name` are mandatory except in
1592         the case of related fields or field extensions.
1593     """
1594     type = 'one2many'
1595     inverse_name = None                 # name of the inverse field
1596     auto_join = False                   # whether joins are generated upon search
1597     limit = None                        # optional limit to use upon read
1598     copyable = False                    # o2m are not copied by default
1599
1600     def __init__(self, comodel_name=None, inverse_name=None, string=None, **kwargs):
1601         super(One2many, self).__init__(
1602             comodel_name=comodel_name,
1603             inverse_name=inverse_name,
1604             string=string,
1605             **kwargs
1606         )
1607
1608     def _setup_regular(self, env):
1609         super(One2many, self)._setup_regular(env)
1610
1611         if self.inverse_name:
1612             # link self to its inverse field and vice-versa
1613             invf = env[self.comodel_name]._fields[self.inverse_name]
1614             # In some rare cases, a `One2many` field can link to `Int` field
1615             # (res_model/res_id pattern). Only inverse the field if this is
1616             # a `Many2one` field.
1617             if isinstance(invf, Many2one):
1618                 self.inverse_fields.append(invf)
1619                 invf.inverse_fields.append(self)
1620
1621     _description_relation_field = property(attrgetter('inverse_name'))
1622
1623     _column_fields_id = property(attrgetter('inverse_name'))
1624     _column_auto_join = property(attrgetter('auto_join'))
1625     _column_limit = property(attrgetter('limit'))
1626
1627
1628 class Many2many(_RelationalMulti):
1629     """ Many2many field; the value of such a field is the recordset.
1630
1631         :param comodel_name: name of the target model (string)
1632
1633         The attribute `comodel_name` is mandatory except in the case of related
1634         fields or field extensions.
1635
1636         :param relation: optional name of the table that stores the relation in
1637             the database (string)
1638
1639         :param column1: optional name of the column referring to "these" records
1640             in the table `relation` (string)
1641
1642         :param column2: optional name of the column referring to "those" records
1643             in the table `relation` (string)
1644
1645         The attributes `relation`, `column1` and `column2` are optional. If not
1646         given, names are automatically generated from model names, provided
1647         `model_name` and `comodel_name` are different!
1648
1649         :param domain: an optional domain to set on candidate values on the
1650             client side (domain or string)
1651
1652         :param context: an optional context to use on the client side when
1653             handling that field (dictionary)
1654
1655         :param limit: optional limit to use upon read (integer)
1656
1657     """
1658     type = 'many2many'
1659     relation = None                     # name of table
1660     column1 = None                      # column of table referring to model
1661     column2 = None                      # column of table referring to comodel
1662     limit = None                        # optional limit to use upon read
1663
1664     def __init__(self, comodel_name=None, relation=None, column1=None, column2=None,
1665                  string=None, **kwargs):
1666         super(Many2many, self).__init__(
1667             comodel_name=comodel_name,
1668             relation=relation,
1669             column1=column1,
1670             column2=column2,
1671             string=string,
1672             **kwargs
1673         )
1674
1675     def _setup_regular(self, env):
1676         super(Many2many, self)._setup_regular(env)
1677
1678         if self.store and not self.relation:
1679             model = env[self.model_name]
1680             column = model._columns[self.name]
1681             if not isinstance(column, fields.function):
1682                 self.relation, self.column1, self.column2 = column._sql_names(model)
1683
1684         if self.relation:
1685             m2m = env.registry._m2m
1686             # if inverse field has already been setup, it is present in m2m
1687             invf = m2m.get((self.relation, self.column2, self.column1))
1688             if invf:
1689                 self.inverse_fields.append(invf)
1690                 invf.inverse_fields.append(self)
1691             else:
1692                 # add self in m2m, so that its inverse field can find it
1693                 m2m[(self.relation, self.column1, self.column2)] = self
1694
1695     _column_rel = property(attrgetter('relation'))
1696     _column_id1 = property(attrgetter('column1'))
1697     _column_id2 = property(attrgetter('column2'))
1698     _column_limit = property(attrgetter('limit'))
1699
1700
1701 class Id(Field):
1702     """ Special case for field 'id'. """
1703     store = True
1704     #: Can't write this!
1705     readonly = True
1706
1707     def __init__(self, string=None, **kwargs):
1708         super(Id, self).__init__(type='integer', string=string, **kwargs)
1709
1710     def to_column(self):
1711         """ to_column() -> fields._column
1712
1713         Whatever
1714         """
1715         return fields.integer('ID')
1716
1717     def __get__(self, record, owner):
1718         if record is None:
1719             return self         # the field is accessed through the class owner
1720         if not record:
1721             return False
1722         return record.ensure_one()._ids[0]
1723
1724     def __set__(self, record, value):
1725         raise TypeError("field 'id' cannot be assigned")
1726
1727
1728 # imported here to avoid dependency cycle issues
1729 from openerp import SUPERUSER_ID
1730 from .exceptions import Warning, AccessError, MissingError
1731 from .models import BaseModel, MAGIC_COLUMNS
1732 from .osv import fields