[IMP] fields: do not copy field objects anymore, but make new instances instead

Because of the parameter overriding mechanism implemented by fields, it is no
longer necessary to copy field objects.  It is even better to no copy them in
the case of related fields.
This commit is contained in:
Raphael Collet 2014-10-09 11:01:23 +02:00
parent 77ae95db5a
commit 8ddf145559
2 changed files with 30 additions and 14 deletions

View File

@ -289,14 +289,9 @@ class Field(object):
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`. """
@ -434,12 +429,17 @@ class Field(object):
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:
@ -458,6 +458,10 @@ class Field(object):
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
@ -486,6 +490,7 @@ class Field(object):
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'))
@ -1354,6 +1359,17 @@ class _Relational(Field):
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'))

View File

@ -811,7 +811,7 @@ class BaseModel(object):
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()
@ -2914,7 +2914,7 @@ class BaseModel(object):
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,