[IMP] fields: log when a stored field depends on a non-stored field
Log an info when a field is computed and stored, but not all its dependencies are stored. Also allow to set explicitly `depends` on a field; this is useful to restrict the dependencies of a related field.
This commit is contained in:
+19
-8
@@ -297,7 +297,7 @@ class Field(MetaField('DummyField', (object,), {})):
|
||||
'index': False, # whether the field is indexed in database
|
||||
'manual': False, # whether the field is a custom field
|
||||
'copy': True, # whether the field is copied over by BaseModel.copy()
|
||||
'depends': (), # collection of field dependencies
|
||||
'depends': None, # collection of field dependencies
|
||||
'recursive': False, # whether self depends on itself
|
||||
'compute': None, # compute(recs) computes field on recs
|
||||
'compute_sudo': False, # whether field should be recomputed as admin
|
||||
@@ -437,6 +437,8 @@ class Field(MetaField('DummyField', (object,), {})):
|
||||
if attrs.get('translate'):
|
||||
# by default, translatable fields are context-dependent
|
||||
attrs['context_dependent'] = attrs.get('context_dependent', True)
|
||||
if 'depends' in attrs:
|
||||
attrs['depends'] = tuple(attrs['depends'])
|
||||
|
||||
return attrs
|
||||
|
||||
@@ -487,16 +489,22 @@ class Field(MetaField('DummyField', (object,), {})):
|
||||
|
||||
def _setup_regular_base(self, model):
|
||||
""" Setup the attributes of a non-related field. """
|
||||
def make_depends(deps):
|
||||
return tuple(deps(model) if callable(deps) else deps)
|
||||
if self.depends is not None:
|
||||
return
|
||||
|
||||
def get_depends(func):
|
||||
deps = getattr(func, '_depends', ())
|
||||
return deps(model) if callable(deps) else deps
|
||||
|
||||
if isinstance(self.compute, pycompat.string_types):
|
||||
# if the compute method has been overridden, concatenate all their _depends
|
||||
self.depends = ()
|
||||
for method in resolve_mro(model, self.compute, callable):
|
||||
self.depends += make_depends(getattr(method, '_depends', ()))
|
||||
self.depends = tuple(
|
||||
dep
|
||||
for method in resolve_mro(model, self.compute, callable)
|
||||
for dep in get_depends(method)
|
||||
)
|
||||
else:
|
||||
self.depends = make_depends(getattr(self.compute, '_depends', ()))
|
||||
self.depends = tuple(get_depends(self.compute))
|
||||
|
||||
def _setup_regular_full(self, model):
|
||||
""" Setup the inverse field(s) of ``self``. """
|
||||
@@ -526,7 +534,8 @@ class Field(MetaField('DummyField', (object,), {})):
|
||||
raise TypeError("Type of related field %s is inconsistent with %s" % (self, field))
|
||||
|
||||
# determine dependencies, compute, inverse, and search
|
||||
self.depends = ('.'.join(self.related),)
|
||||
if self.depends is None:
|
||||
self.depends = ('.'.join(self.related),)
|
||||
self.compute = self._compute_related
|
||||
if not (self.readonly or field.readonly):
|
||||
self.inverse = self._inverse_related
|
||||
@@ -698,6 +707,8 @@ class Field(MetaField('DummyField', (object,), {})):
|
||||
def setup_triggers(self, model):
|
||||
""" Add the necessary triggers to invalidate/recompute ``self``. """
|
||||
for model, field, path in self.resolve_deps(model):
|
||||
if self.store and not field.store:
|
||||
_logger.info("Field %s depends on non-stored field %s", self, field)
|
||||
if field is not self:
|
||||
path_str = None if path is None else ('.'.join(path) or 'id')
|
||||
model._field_triggers.add(field, (self, path_str))
|
||||
|
||||
Reference in New Issue
Block a user