From 8ddf14555962a7af5c4a9f2f201cccf4a528ebd0 Mon Sep 17 00:00:00 2001 From: Raphael Collet Date: Thu, 9 Oct 2014 11:01:23 +0200 Subject: [PATCH] [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. --- openerp/fields.py | 40 ++++++++++++++++++++++++++++------------ openerp/models.py | 4 ++-- 2 files changed, 30 insertions(+), 14 deletions(-) diff --git a/openerp/fields.py b/openerp/fields.py index df1433087cb..9165ddfde1f 100644 --- a/openerp/fields.py +++ b/openerp/fields.py @@ -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')) diff --git a/openerp/models.py b/openerp/models.py index 2562e108410..bb54260e5fe 100644 --- a/openerp/models.py +++ b/openerp/models.py @@ -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,