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