[IMP] fields: do not copy field objects anymore, but make new instances instead
authorRaphael Collet <rco@openerp.com>
Thu, 9 Oct 2014 09:01:23 +0000 (11:01 +0200)
committerRaphael Collet <rco@openerp.com>
Thu, 9 Oct 2014 13:05:15 +0000 (15:05 +0200)
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
openerp/models.py

index df14330..9165ddf 100644 (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'))
 
index 2562e10..bb54260 100644 (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,