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