[REF] fields: setup and use of depends_context
closes odoo/odoo#36795 Signed-off-by: Raphael Collet (rco) <rco@openerp.com>
This commit is contained in:
+25
-31
@@ -213,9 +213,9 @@ def depends(*args):
|
||||
|
||||
|
||||
def depends_context(*args):
|
||||
""" Return a decorator that specifies the context dependencies of a non-stored "compute"
|
||||
method (for new-style function fields). Each argument must be a string
|
||||
that consists in a key in the context::
|
||||
""" Return a decorator that specifies the context dependencies of a
|
||||
non-stored "compute" method. Each argument is a key in the context's
|
||||
dictionary::
|
||||
|
||||
price = fields.Float(compute='_compute_product_price')
|
||||
|
||||
@@ -227,6 +227,12 @@ def depends_context(*args):
|
||||
else:
|
||||
pricelist = self.env['product.pricelist'].get_default_pricelist()
|
||||
product.price = pricelist.get_products_price(product).get(product.id, 0.0)
|
||||
|
||||
All dependencies must be hashable. The following keys have special
|
||||
support:
|
||||
- 'force_company' (value in context or current company id),
|
||||
- 'uid' (current user id and superuser flag),
|
||||
- 'active_test' (value in env.context or value in field.context).
|
||||
"""
|
||||
return attrsetter('_depends_context', args)
|
||||
|
||||
@@ -693,25 +699,10 @@ class Cache(object):
|
||||
# {field: {record_id: value}}
|
||||
self._data = defaultdict(dict)
|
||||
|
||||
def _get_context_key(self, env, field):
|
||||
get_context = env.context.get
|
||||
|
||||
def get(key):
|
||||
if key == 'force_company':
|
||||
return get_context('force_company') or env.company.id
|
||||
elif key == 'uid':
|
||||
return (env.uid, env.su)
|
||||
elif key == 'active_test':
|
||||
return get_context('active_test', field.context.get('active_test', True))
|
||||
else:
|
||||
return get_context(key)
|
||||
|
||||
return tuple(get(key) for key in field.depends_context)
|
||||
|
||||
def contains(self, record, field):
|
||||
""" Return whether ``record`` has a value for ``field``. """
|
||||
if field.depends_context:
|
||||
key = self._get_context_key(record.env, field)
|
||||
key = field.cache_key(record.env)
|
||||
return key in self._data.get(field, {}).get(record.id, {})
|
||||
return record.id in self._data.get(field, ())
|
||||
|
||||
@@ -720,8 +711,7 @@ class Cache(object):
|
||||
try:
|
||||
value = self._data[field][record._ids[0]]
|
||||
if field.depends_context:
|
||||
key = self._get_context_key(record.env, field)
|
||||
value = value[key]
|
||||
value = value[field.cache_key(record.env)]
|
||||
return value
|
||||
except KeyError:
|
||||
if default is NOTHING:
|
||||
@@ -731,7 +721,7 @@ class Cache(object):
|
||||
def set(self, record, field, value):
|
||||
""" Set the value of ``field`` for ``record``. """
|
||||
if field.depends_context:
|
||||
key = self._get_context_key(record.env, field)
|
||||
key = field.cache_key(record.env)
|
||||
self._data[field].setdefault(record._ids[0], {})[key] = value
|
||||
else:
|
||||
self._data[field][record._ids[0]] = value
|
||||
@@ -739,7 +729,7 @@ class Cache(object):
|
||||
def update(self, records, field, values):
|
||||
""" Set the values of ``field`` for several ``records``. """
|
||||
if field.depends_context:
|
||||
key = self._get_context_key(records.env, field)
|
||||
key = field.cache_key(records.env)
|
||||
field_cache = self._data[field]
|
||||
for record_id, value in zip(records._ids, values):
|
||||
field_cache.setdefault(record_id, {})[key] = value
|
||||
@@ -756,10 +746,10 @@ class Cache(object):
|
||||
def get_values(self, records, field):
|
||||
""" Return the cached values of ``field`` for ``records``. """
|
||||
field_cache = self._data[field]
|
||||
key = self._get_context_key(records.env, field) if field.depends_context else None
|
||||
key = field.cache_key(records.env) if field.depends_context else None
|
||||
for record_id in records._ids:
|
||||
try:
|
||||
if key:
|
||||
if key is not None:
|
||||
yield field_cache[record_id][key]
|
||||
else:
|
||||
yield field_cache[record_id]
|
||||
@@ -769,11 +759,11 @@ class Cache(object):
|
||||
def get_records_different_from(self, records, field, value):
|
||||
""" Return the subset of ``records`` that has not ``value`` for ``field``. """
|
||||
field_cache = self._data[field]
|
||||
key = self._get_context_key(records.env, field) if field.depends_context else None
|
||||
key = field.cache_key(records.env) if field.depends_context else None
|
||||
ids = []
|
||||
for record_id in records._ids:
|
||||
try:
|
||||
if key:
|
||||
if key is not None:
|
||||
val = field_cache[record_id][key]
|
||||
else:
|
||||
val = field_cache[record_id]
|
||||
@@ -787,10 +777,14 @@ class Cache(object):
|
||||
def get_fields(self, record):
|
||||
""" Return the fields with a value for ``record``. """
|
||||
for name, field in record._fields.items():
|
||||
values = self._data.get(field, ())
|
||||
key = self._get_context_key(record.env, field) if field.depends_context else None
|
||||
if name != 'id' and record.id in values and (not key or key in values[record.id]):
|
||||
yield field
|
||||
if name == 'id':
|
||||
continue
|
||||
values = self._data.get(field, {})
|
||||
if record.id not in values:
|
||||
continue
|
||||
if field.depends_context and field.cache_key(record.env) not in values[record.id]:
|
||||
continue
|
||||
yield field
|
||||
|
||||
def get_records(self, model, field):
|
||||
""" Return the records of ``model`` that have a value for ``field``. """
|
||||
|
||||
+35
-21
@@ -498,30 +498,24 @@ class Field(MetaField('DummyField', (object,), {})):
|
||||
if self.depends is not None:
|
||||
return
|
||||
|
||||
def get_depends(func):
|
||||
deps = getattr(func, '_depends', ())
|
||||
return deps(model) if callable(deps) else deps
|
||||
|
||||
def get_depends_context(func):
|
||||
return getattr(func, '_depends_context', ())
|
||||
|
||||
# determine the functions implementing self.compute
|
||||
if isinstance(self.compute, str):
|
||||
# if the compute method has been overridden, concatenate all their _depends
|
||||
self.depends = tuple(
|
||||
dep
|
||||
for method in resolve_mro(model, self.compute, callable)
|
||||
for dep in get_depends(method)
|
||||
)
|
||||
depends_context = tuple(
|
||||
dep
|
||||
for method in resolve_mro(model, self.compute, callable)
|
||||
for dep in get_depends_context(method)
|
||||
)
|
||||
funcs = resolve_mro(model, self.compute, callable)
|
||||
elif self.compute:
|
||||
funcs = [self.compute]
|
||||
else:
|
||||
self.depends = tuple(get_depends(self.compute))
|
||||
depends_context = tuple(get_depends_context(self.compute))
|
||||
funcs = []
|
||||
|
||||
self.depends_context = (self.depends_context or ()) + depends_context
|
||||
# collect depends and depends_context
|
||||
depends = []
|
||||
depends_context = list(self.depends_context or ())
|
||||
for func in funcs:
|
||||
deps = getattr(func, '_depends', ())
|
||||
depends.extend(deps(model) if callable(deps) else deps)
|
||||
depends_context.extend(getattr(func, '_depends_context', ()))
|
||||
|
||||
self.depends = tuple(depends)
|
||||
self.depends_context = tuple(depends_context)
|
||||
|
||||
# display_name may depend on context['lang'] (`test_lp1071710`)
|
||||
if self.automatic and self.name == 'display_name' and model._rec_name:
|
||||
@@ -698,6 +692,26 @@ class Field(MetaField('DummyField', (object,), {})):
|
||||
Property = records.env['ir.property']
|
||||
return Property.search_multi(self.name, self.model_name, operator, value)
|
||||
|
||||
#
|
||||
# Cache key for context-dependent fields
|
||||
#
|
||||
|
||||
def cache_key(self, env):
|
||||
""" Return the cache key corresponding to ``self.depends_context``. """
|
||||
get_context = env.context.get
|
||||
|
||||
def get(key):
|
||||
if key == 'force_company':
|
||||
return get_context('force_company') or env.company.id
|
||||
elif key == 'uid':
|
||||
return (env.uid, env.su)
|
||||
elif key == 'active_test':
|
||||
return get_context('active_test', self.context.get('active_test', True))
|
||||
else:
|
||||
return get_context(key)
|
||||
|
||||
return tuple(get(key) for key in self.depends_context)
|
||||
|
||||
#
|
||||
# Setup of field triggers
|
||||
#
|
||||
|
||||
Reference in New Issue
Block a user