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