Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 10 additions & 4 deletions trytond/trytond/model/fields/many2many.py
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ def get(self, ids, model, name, values=None):

Relation = self.get_relation()
origin_field = Relation._fields[self.origin]
reference_key = origin_field._type == 'reference'

if (not isinstance(origin_field, Function)
or hasattr(Relation, 'order_' + self.field)):
Expand All @@ -153,7 +154,7 @@ def get(self, ids, model, name, values=None):

relations = []
for sub_ids in grouped_slice(ids):
if origin_field._type == 'reference':
if reference_key:
references = ['%s,%s' % (model.__name__, x) for x in sub_ids]
clause = [(self.origin, 'in', references)]
else:
Expand All @@ -162,11 +163,16 @@ def get(self, ids, model, name, values=None):
if self.filter:
clause.append((self.target, 'where', self.filter))
relations.append(Relation.search(clause, order=order))
relations = Relation.browse(list(chain(*relations)))
relations = Relation.read(
list(chain(*relations)), [self.origin, self.target])

for relation in relations:
origin_id = getattr(relation, self.origin).id
res[origin_id].append(getattr(relation, self.target).id)
if reference_key:
_, origin_id = relation[self.origin].split(',', 1)
origin_id = int(origin_id)
else:
origin_id = relation[self.origin]
res[origin_id].append(relation[self.target])
return dict((key, tuple(value)) for key, value in res.items())

def set(self, Model, name, ids, values, *args):
Expand Down
13 changes: 9 additions & 4 deletions trytond/trytond/model/fields/one2many.py
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@ def get(self, ids, model, name, values=None):
'''
Target = self.get_target()
field = Target._fields[self.field]
reference_o2m = field._type == 'reference'
res = {}
for i in ids:
res[i] = []
Expand All @@ -158,19 +159,23 @@ def get(self, ids, model, name, values=None):
order += Target._order
targets = []
for sub_ids in grouped_slice(ids):
if field._type == 'reference':
if reference_o2m:
references = ['%s,%s' % (model.__name__, x) for x in sub_ids]
clause = [(self.field, 'in', references)]
else:
clause = [(self.field, 'in', list(sub_ids))]
if self.filter:
clause.append(self.filter)
targets.append(Target.search(clause, order=order))
targets = Target.browse(list(chain(*targets)))
targets = Target.read(list(chain(*targets)), ['id', self.field])

for target in targets:
origin_id = getattr(target, self.field).id
res[origin_id].append(target.id)
if reference_o2m:
_, origin_id = target[self.field].split(',', 1)
origin_id = int(origin_id)
else:
origin_id = target[self.field]
res[origin_id].append(target['id'])
return dict((key, tuple(value)) for key, value in res.items())

def set(self, Model, name, ids, values, *args):
Expand Down
66 changes: 40 additions & 26 deletions trytond/trytond/model/modelstorage.py
Original file line number Diff line number Diff line change
Expand Up @@ -1663,6 +1663,8 @@ def __getattr__(self, name):
except KeyError:
skip_eager = False

pool = Pool()

# build the list of fields we will fetch
ffields = {
name: field,
Expand All @@ -1676,7 +1678,7 @@ def __getattr__(self, name):
multiple_getter = field.getter

if load_eager or multiple_getter:
FieldAccess = Pool().get('ir.model.field.access')
FieldAccess = pool.get('ir.model.field.access')
fread_accesses = {}
fread_accesses.update(FieldAccess.check(self.__name__,
list(self._fields.keys()), 'read', access=True))
Expand Down Expand Up @@ -1752,6 +1754,30 @@ def unique(ids):
islice(self._ids, 0, max(index - 1, 0)))
ids = islice(unique(filter(filter_, ids)), read_size)

kwargs_cache = {}
transaction = Transaction()

def create_instances(Model, value, cache_key=None):
cache_key = (Model, cache_key)
if cache_key in kwargs_cache:
kwargs = kwargs_cache[cache_key]
else:
if cache_key not in model2cache:
model2cache[cache_key] = local_cache(Model, transaction)
kwargs_cache[cache_key] = kwargs = {
'_local_cache': model2cache[cache_key],
'_ids': model2ids.setdefault(cache_key, []),
'_transaction_cache': transaction.get_cache(),
'_transaction': transaction,
}
ids = kwargs['_ids']
if field._type in ('many2one', 'one2one', 'reference'):
ids.append(value)
return Model(value, **kwargs)
elif field._type in ('one2many', 'many2many'):
ids.extend(value)
return tuple(Model(id, **kwargs) for id in value)

def instantiate(field, value, data):
if field._type in ('many2one', 'one2one', 'reference'):
# ABDC: Fix when data is an empty string, we should return
Expand All @@ -1764,7 +1790,7 @@ def instantiate(field, value, data):
try:
if field._type == 'reference':
model_name, record_id = value.split(',')
Model = Pool().get(model_name)
Model = pool.get(model_name)
try:
record_id = int(record_id)
except ValueError:
Expand All @@ -1777,30 +1803,18 @@ def instantiate(field, value, data):
except KeyError:
return value
transaction = Transaction()
ctx = {}
if field.context:
pyson_context = PYSONEncoder().encode(field.context)
ctx.update(PYSONDecoder(data).decode(pyson_context))
datetime_ = None
if getattr(field, 'datetime_field', None):
datetime_ = data.get(field.datetime_field)
ctx = {'_datetime': datetime_}
with transaction.set_context(**ctx):
kwargs = {}
key = (Model, freeze(ctx))
if key not in model2cache:
model2cache[key] = local_cache(Model, transaction)
kwargs['_local_cache'] = model2cache[key]
kwargs['_ids'] = ids = model2ids.setdefault(key, [])
kwargs['_transaction_cache'] = transaction.get_cache()
kwargs['_transaction'] = transaction
if field._type in ('many2one', 'one2one', 'reference'):
value = int(value)
ids.append(value)
return Model(value, **kwargs)
elif field._type in ('one2many', 'many2many'):
ids.extend(int(x) for x in value)
return tuple(Model(id, **kwargs) for id in value)
if ((dt_field := getattr(field, 'datetime_field', None))
or field.context):
ctx = {}
if field.context:
pyson_context = PYSONEncoder().encode(field.context)
ctx.update(PYSONDecoder(data).decode(pyson_context))
if dt_field:
ctx['_datetime'] = data.get(dt_field)
with transaction.set_context(**ctx):
return create_instances(Model, value, freeze(ctx))
else:
return create_instances(Model, value)

model2ids = {}
model2cache = {}
Expand Down