From 2680d1b746baceb60ca6cf4feee95dbf2c0bd5fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Mon, 24 Feb 2014 19:15:57 +0100 Subject: [PATCH] Use a sequence of ids, values to set fields review3331003 --- CHANGELOG | 1 + trytond/model/fields/function.py | 8 +++- trytond/model/fields/many2many.py | 71 +++++++++++++++++-------------- trytond/model/fields/one2many.py | 71 ++++++++++++++++++------------- trytond/model/fields/one2one.py | 39 ++++++++--------- trytond/model/fields/property.py | 22 +++++----- trytond/model/modelsql.py | 15 ++++++- 7 files changed, 129 insertions(+), 98 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 8080ead959..b521d1327d 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,4 @@ +* Use a sequence of ids, values to set fields * Client side actions on button and wizard * Add depends attribute to data tag * Add tree_invisible attribute to button in tree view diff --git a/trytond/model/fields/function.py b/trytond/model/fields/function.py index 2ebc511963..d5489b7820 100644 --- a/trytond/model/fields/function.py +++ b/trytond/model/fields/function.py @@ -91,12 +91,16 @@ class Function(Field): name = [name] return call(name) - def set(self, ids, Model, name, value): + def set(self, Model, name, ids, value, *args): ''' Call the setter. ''' if self.setter: - getattr(Model, self.setter)(Model.browse(ids), name, value) + # TODO change setter API to use sequence of records, value + setter = getattr(Model, self.setter) + args = iter((ids, value) + args) + for ids, value in zip(args, args): + setter(Model.browse(ids), name, value) def __set__(self, inst, value): self._field.__set__(inst, value) diff --git a/trytond/model/fields/many2many.py b/trytond/model/fields/many2many.py index 8fff8a5359..ea85b4febd 100644 --- a/trytond/model/fields/many2many.py +++ b/trytond/model/fields/many2many.py @@ -95,7 +95,7 @@ class Many2Many(Field): res[origin_id].append(getattr(relation, self.target).id) return dict((key, tuple(value)) for key, value in res.iteritems()) - def set(self, ids, model, name, values): + def set(self, Model, name, ids, values, *args): ''' Set the values. @@ -113,40 +113,41 @@ class Many2Many(Field): Relation = pool.get(self.relation_name) Target = self.get_target() origin_field = Relation._fields[self.origin] + relation_to_create = [] + relation_to_delete = [] + target_to_write = [] + target_to_delete = [] def search_clause(ids): if origin_field._type == 'reference': - references = ['%s,%s' % (model.__name__, x) for x in ids] + references = ['%s,%s' % (Model.__name__, x) for x in ids] return (self.origin, 'in', references) else: return (self.origin, 'in', ids) def field_value(record_id): if origin_field._type == 'reference': - return '%s,%s' % (model.__name__, record_id) + return '%s,%s' % (Model.__name__, record_id) else: return record_id - def create(vlist): - to_create = [] + def create(ids, vlist): for record_id in ids: for new in Target.create(vlist): - to_create.append({ + relation_to_create.append({ self.origin: field_value(record_id), self.target: new.id, }) - if to_create: - Relation.create(to_create) - def write(*args): + def write(_, *args): actions = iter(args) - Target.write(*sum(((Target.browse(ids), values) + target_to_write.extend(sum(((Target.browse(ids), values) for ids, values in zip(actions, actions)), ())) - def delete(target_ids): - Target.delete(Target.browse(target_ids)) + def delete(_, target_ids): + target_to_delete.extend(Target.browse(target_ids)) - def add(target_ids): + def add(ids, target_ids): target_ids = map(int, target_ids) if not target_ids: return @@ -160,48 +161,40 @@ class Many2Many(Field): ]) for relation in relations: existing_ids.add(getattr(relation, self.target).id) - to_create = [] for new_id in target_ids: if new_id in existing_ids: continue for record_id in ids: - to_create.append({ + relation_to_create.append({ self.origin: field_value(record_id), self.target: new_id, }) - if to_create: - Relation.create(to_create) - def remove(target_ids): + def remove(ids, target_ids): target_ids = map(int, target_ids) if not target_ids: return - relations = [] in_max = Transaction().cursor.IN_MAX for i in range(0, len(target_ids), in_max): sub_ids = target_ids[i:i + in_max] - relations += Relation.search([ - search_clause(ids), - (self.target, 'in', sub_ids), - ]) - Relation.delete(relations) + relation_to_delete.extend(Relation.search([ + search_clause(ids), + (self.target, 'in', sub_ids), + ])) - def copy(copy_ids, default=None): + def copy(ids, copy_ids, default=None): copy_ids = map(int, copy_ids) if default is None: default = {} default = default.copy() - to_create = [] copies = Target.browse(copy_ids) for new in Target.copy(copies, default=default): for record_id in ids: - to_create.append({ + relation_to_create.append({ self.origin: field_value(record_id), self.target: new.id, }) - if to_create: - Relation.create(to_create) actions = { 'create': create, @@ -211,10 +204,22 @@ class Many2Many(Field): 'remove': remove, 'copy': copy, } - for value in values: - action = value[0] - args = value[1:] - actions[action](*args) + args = iter((ids, values) + args) + for ids, values in zip(args, args): + if not values: + continue + for value in values: + action = value[0] + args = value[1:] + actions[action](ids, *args) + if relation_to_create: + Relation.create(relation_to_create) + if relation_to_delete: + Relation.delete(relation_to_delete) + if target_to_write: + Target.write(*target_to_write) + if target_to_delete: + Target.delete(target_to_delete) def get_target(self): 'Return the target model' diff --git a/trytond/model/fields/one2many.py b/trytond/model/fields/one2many.py index 6156120af5..a6f2c286b5 100644 --- a/trytond/model/fields/one2many.py +++ b/trytond/model/fields/one2many.py @@ -102,7 +102,7 @@ class One2Many(Field): res[origin_id].append(target.id) return dict((key, tuple(value)) for key, value in res.iteritems()) - def set(self, ids, model, name, values): + def set(self, Model, name, ids, values, *args): ''' Set the values. values: A list of tuples: @@ -113,66 +113,67 @@ class One2Many(Field): (``remove``, ````), (``copy``, ````, ``[{: value}, ...]``) ''' - if not values: - return Target = self.get_target() field = Target._fields[self.field] + to_create = [] + to_write = [] + to_delete = [] def search_clause(ids): if field._type == 'reference': - references = ['%s,%s' % (model.__name__, x) for x in ids] + references = ['%s,%s' % (Model.__name__, x) for x in ids] return (self.field, 'in', references) else: return (self.field, 'in', ids) def field_value(record_id): if field._type == 'reference': - return '%s,%s' % (model.__name__, record_id) + return '%s,%s' % (Model.__name__, record_id) else: return record_id - def create(vlist): - to_create = [] + def create(ids, vlist): for record_id in ids: value = field_value(record_id) for values in vlist: values = values.copy() values[self.field] = value to_create.append(values) - if to_create: - Target.create(to_create) - def write(*args): + def write(_, *args): actions = iter(args) - Target.write(*sum(((Target.browse(ids), values) + to_write.extend(sum(((Target.browse(ids), values) for ids, values in zip(actions, actions)), ())) - def delete(target_ids): - Target.delete(Target.browse(target_ids)) + def delete(_, target_ids): + to_delete.extend(Target.browse(target_ids)) - def add(target_ids): + def add(ids, target_ids): target_ids = map(int, target_ids) if not target_ids: return targets = Target.browse(target_ids) for record_id in ids: - Target.write(targets, { - self.field: field_value(record_id), - }) + to_write.extend((targets, { + self.field: field_value(record_id), + })) - def remove(target_ids): + def remove(ids, target_ids): target_ids = map(int, target_ids) if not target_ids: return - targets = Target.search([ - search_clause(ids), - ('id', 'in', target_ids), - ]) - Target.write(targets, { - self.field: None, - }) + in_max = Transaction().cursor.IN_MAX + for i in range(0, len(target_ids), in_max): + sub_ids = target_ids[i:i + in_max] + targets = Target.search([ + search_clause(ids), + ('id', 'in', sub_ids), + ]) + to_write.extend((targets, { + self.field: None, + })) - def copy(copy_ids, default=None): + def copy(ids, copy_ids, default=None): copy_ids = map(int, copy_ids) if default is None: @@ -191,10 +192,20 @@ class One2Many(Field): 'remove': remove, 'copy': copy, } - for value in values: - action = value[0] - args = value[1:] - actions[action](*args) + args = iter((ids, values) + args) + for ids, values in zip(args, args): + if not values: + continue + for value in values: + action = value[0] + args = value[1:] + actions[action](ids, *args) + if to_create: + Target.create(to_create) + if to_write: + Target.write(*to_write) + if to_delete: + Target.delete(to_delete) def get_target(self): 'Return the target Model' diff --git a/trytond/model/fields/one2one.py b/trytond/model/fields/one2one.py index eea5ac8168..7e29afd597 100644 --- a/trytond/model/fields/one2one.py +++ b/trytond/model/fields/one2one.py @@ -28,30 +28,31 @@ class One2One(Many2Many): res[i] = vals[0] if vals else False return res - def set(self, ids, model, name, value): + def set(self, Model, name, ids, value, *args): ''' Set the values. - - :param ids: A list of ids - :param model: A string with the name of the model - :param name: A string with the name of the field - :param value: The id to link ''' pool = Pool() Relation = pool.get(self.relation_name) - relations = Relation.search([ - (self.origin, 'in', ids), - ]) - Relation.delete(relations) - if value: - to_create = [] - for record_id in ids: - to_create.append({ - self.origin: record_id, - self.target: value, - }) - if to_create: - Relation.create(to_create) + to_delete = [] + to_create = [] + args = iter((ids, value) + args) + for ids, value in zip(args, args): + relations = Relation.search([ + (self.origin, 'in', ids), + ]) + to_delete.extend(relations) + if value: + to_create = [] + for record_id in ids: + to_create.append({ + self.origin: record_id, + self.target: value, + }) + if to_delete: + Relation.delete(to_delete) + if to_create: + Relation.create(to_create) def __set__(self, inst, value): Target = self.get_target() diff --git a/trytond/model/fields/property.py b/trytond/model/fields/property.py index 568b845b14..13737dde77 100644 --- a/trytond/model/fields/property.py +++ b/trytond/model/fields/property.py @@ -46,23 +46,21 @@ class Property(Function): Property = pool.get('ir.property') return Property.get(name, model.__name__, ids) - def set(self, ids, model, name, value): + def set(self, Model, name, ids, value, *args): ''' Set the property. - - :param ids: A list of ids. - :param model: The model. - :param name: The name of the field. - :param value: The value to set. ''' pool = Pool() Property = pool.get('ir.property') - if value is not None: - prop_value = '%s,%s' % (getattr(self, 'model_name', ''), - str(value)) - else: - prop_value = None - Property.set(name, model.__name__, ids, prop_value) + args = iter((ids, value) + args) + for ids, value in zip(args, args): + if value is not None: + prop_value = '%s,%s' % (getattr(self, 'model_name', ''), + str(value)) + else: + prop_value = None + # TODO change set API to use sequence of records, value + Property.set(name, Model.__name__, ids, prop_value) def convert_domain(self, domain, tables, Model): pool = Pool() diff --git a/trytond/model/modelsql.py b/trytond/model/modelsql.py index b37c0028f5..1308b57309 100644 --- a/trytond/model/modelsql.py +++ b/trytond/model/modelsql.py @@ -379,6 +379,7 @@ class ModelSQL(ModelStorage): set()).update(new_ids) translation_values = {} + fields_to_set = {} for values, new_id in izip(vlist, new_ids): for fname, value in values.iteritems(): field = cls._fields[fname] @@ -387,13 +388,18 @@ class ModelSQL(ModelStorage): translation_values.setdefault( '%s,%s' % (cls.__name__, fname), {})[new_id] = value if hasattr(field, 'set'): - field.set([new_id], cls, fname, value) + fields_to_set.setdefault(fname, []).extend( + ([new_id], value)) if translation_values: for name, translations in translation_values.iteritems(): Translation.set_ids(name, 'model', Transaction().language, translations.keys(), translations.values()) + for fname, fargs in fields_to_set.iteritems(): + field = cls._fields[fname] + field.set(cls, fname, *fargs) + cls.__insert_history(new_ids) records = cls.browse(new_ids) @@ -657,6 +663,7 @@ class ModelSQL(ModelStorage): cls.__check_timestamp(all_ids) + fields_to_set = {} actions = iter((records, values) + args) for records, values in zip(actions, actions): ids = [r.id for r in records] @@ -717,12 +724,16 @@ class ModelSQL(ModelStorage): '%s,%s' % (cls.__name__, fname), 'model', transaction.language, ids, [value] * len(ids)) if hasattr(field, 'set'): - field.set(ids, cls, fname, value) + fields_to_set.setdefault(fname, []).extend((ids, value)) field_names = cls._fields.keys() cls._update_mptt(field_names, [ids] * len(field_names), values) all_field_names |= set(values.keys()) + for fname, fargs in fields_to_set.iteritems(): + field = cls._fields[fname] + field.set(cls, fname, *fargs) + cls.__insert_history(all_ids) for i in range(0, len(all_records), RECORD_CACHE_SIZE): cls._validate(all_records[i:i + RECORD_CACHE_SIZE],