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