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