self._attrs = {key: val for key, val in kwargs.iteritems() if val is not None}
self._free_attrs = []
- def copy(self, **kwargs):
- """ copy(item) -> test
-
- make a copy of `self`, possibly modified with parameters `kwargs` """
- field = copy(self)
- field._attrs = {key: val for key, val in kwargs.iteritems() if val is not None}
- field._free_attrs = list(self._free_attrs)
- return field
+ def new(self, **kwargs):
+ """ Return a field of the same type as `self`, with its own parameters. """
+ return type(self)(**kwargs)
def set_class_name(self, cls, name):
""" Assign the model class and field name of `self`. """
if isinstance(self.related, basestring):
self.related = tuple(self.related.split('.'))
- # determine the related field, and make sure it is set up
+ # determine the chain of fields, and make sure they are all set up
+ fields = []
recs = env[self.model_name]
- for name in self.related[:-1]:
+ for name in self.related:
+ fields.append(recs._fields[name])
recs = recs[name]
- field = self.related_field = recs._fields[self.related[-1]]
- field.setup(env)
+
+ for field in fields:
+ field.setup(env)
+
+ self.related_field = field = fields[-1]
# check type consistency
if self.type != field.type:
if not getattr(self, attr):
setattr(self, attr, getattr(field, prop))
+ # special case: required
+ if not self.required:
+ self.required = all(field.required for field in fields)
+
def _compute_related(self, records):
""" Compute the related field `self` on `records`. """
# when related_sudo, bypass access rights checks when reading values
return [('.'.join(self.related), operator, value)]
# properties used by _setup_related() to copy values from related field
+ _related_comodel_name = property(attrgetter('comodel_name'))
_related_string = property(attrgetter('string'))
_related_help = property(attrgetter('help'))
_related_readonly = property(attrgetter('readonly'))
assert self.comodel_name in env.registry, \
"Field %s with unknown comodel_name %r" % (self, self.comodel_name)
+ @property
+ def _related_domain(self):
+ if callable(self.domain):
+ # will be called with another model than self's
+ return lambda recs: self.domain(recs.env[self.model_name])
+ else:
+ # maybe not correct if domain is a string...
+ return self.domain
+
+ _related_context = property(attrgetter('context'))
+
_description_relation = property(attrgetter('comodel_name'))
_description_context = property(attrgetter('context'))
cls._fields = {}
for attr, field in getmembers(cls, Field.__instancecheck__):
if not field.inherited:
- cls._add_field(attr, field.copy())
+ cls._add_field(attr, field.new())
# introduce magic fields
cls._add_magic_fields()
for parent_model, parent_field in reversed(cls._inherits.items()):
for attr, field in cls.pool[parent_model]._fields.iteritems():
if attr not in cls._fields:
- cls._add_field(attr, field.copy(
+ cls._add_field(attr, field.new(
inherited=True,
related=(parent_field, attr),
related_sudo=False,