Use a sequence of records, values in write
issue3499 review1641003
This commit is contained in:
1 parent
c46a026c40
commit
f52fe8e45f
23 files changed
+291
-199
No files matched your search
@@ -1,3 +1,4 @@
|
||||
* Use a sequence of records, values in write
|
||||
* set_context of Transaction.set_user is restricted to root
|
||||
* Add a "copy" action to One2Many and Many2Many's set method
|
||||
* Force UTC as timezone (migration script available on tryton-tools)
|
||||
|
||||
@@ -495,8 +495,8 @@ This field accepts as written value a list of tuples like this:
|
||||
- ``('create', [{<field name>: value, ...}, ...])``: it will create new
|
||||
target records and link them to this one.
|
||||
|
||||
- ``('write'[, ids, ...], {<field name>: value, ...})``: it will write
|
||||
values to target ids.
|
||||
- ``('write'[[, ids, ...], {<field name>: value, ...}, ...])``: it will
|
||||
write values to target ids.
|
||||
|
||||
- ``('delete'[, ids, ...])``: it will delete the target ids.
|
||||
|
||||
|
||||
@@ -238,7 +238,7 @@ CLass methods:
|
||||
Return a list of values for the ids. If ``fields_names`` is set, there will
|
||||
be only values for these fields otherwise it will be for all fields.
|
||||
|
||||
.. classmethod:: ModelStorage.write(records, values)
|
||||
.. classmethod:: ModelStorage.write(records, values, [[records, values], ...])
|
||||
|
||||
Write ``values`` on the list of records. ``values`` is a dictionary with
|
||||
fields names as key and writen values as value.
|
||||
|
||||
+1
-1
@@ -17,7 +17,7 @@ Instance attributes are:
|
||||
|
||||
.. attribute:: RPC.instantiate
|
||||
|
||||
The position of the argument to be instanciated
|
||||
The position or the slice of the argument to be instanciated
|
||||
|
||||
.. attribute:: RPC.result
|
||||
|
||||
|
||||
+67
-36
@@ -402,6 +402,8 @@ class TrytondXmlHandler(sax.handler.ContentHandler):
|
||||
self.module_state = module_state
|
||||
self.grouped = None
|
||||
self.grouped_creations = defaultdict(dict)
|
||||
self.grouped_write = defaultdict(list)
|
||||
self.grouped_model_data = []
|
||||
self.skip_data = False
|
||||
|
||||
# Tag handlders are used to delegate the processing
|
||||
@@ -475,6 +477,13 @@ class TrytondXmlHandler(sax.handler.ContentHandler):
|
||||
for model, values in self.grouped_creations.iteritems():
|
||||
self.create_records(model, values.values(), values.keys())
|
||||
self.grouped_creations.clear()
|
||||
for key, actions in self.grouped_write.iteritems():
|
||||
module, model = key
|
||||
self.write_records(module, model, *actions)
|
||||
self.grouped_write.clear()
|
||||
if self.grouped_model_data:
|
||||
self.ModelData.write(*self.grouped_model_data)
|
||||
del self.grouped_model_data[:]
|
||||
|
||||
# Closing tag found, if we are in a delegation the handler
|
||||
# know what to do:
|
||||
@@ -664,42 +673,12 @@ class TrytondXmlHandler(sax.handler.ContentHandler):
|
||||
# and no user changed the value in the db:
|
||||
to_update[key] = values[key]
|
||||
|
||||
# if there is values to update:
|
||||
if to_update:
|
||||
# write the values in the db:
|
||||
with Transaction().set_context(
|
||||
module=module, language='en_US'):
|
||||
Model.write([record], to_update)
|
||||
self.fs2db.reset_browsercord(
|
||||
module, Model.__name__, [record.id])
|
||||
|
||||
if to_update:
|
||||
# re-read it: this ensure that we store the real value
|
||||
# in the model_data table:
|
||||
record = self.fs2db.get_browserecord(
|
||||
module, Model.__name__, record.id)
|
||||
if not record:
|
||||
record = Model(record.id)
|
||||
for key in to_update:
|
||||
values[key] = self._clean_value(key, record)
|
||||
|
||||
if module != self.module:
|
||||
temp_values = old_values.copy()
|
||||
temp_values.update(values)
|
||||
values = temp_values
|
||||
|
||||
if values != old_values:
|
||||
self.ModelData.write([self.ModelData(mdata_id)], {
|
||||
'fs_id': fs_id,
|
||||
'model': model,
|
||||
'module': module,
|
||||
'db_id': record.id,
|
||||
'values': str(values),
|
||||
'date_update': datetime.datetime.now(),
|
||||
})
|
||||
# reset_browsercord to keep cache memory low
|
||||
self.fs2db.reset_browsercord(module, Model.__name__, [record.id])
|
||||
|
||||
if self.grouped:
|
||||
self.grouped_write[(module, model)].extend(
|
||||
(record, to_update, old_values, fs_id, mdata_id))
|
||||
else:
|
||||
self.write_records(module, model, record, to_update,
|
||||
old_values, fs_id, mdata_id)
|
||||
else:
|
||||
if self.grouped:
|
||||
self.grouped_creations[model][fs_id] = values
|
||||
@@ -739,6 +718,58 @@ class TrytondXmlHandler(sax.handler.ContentHandler):
|
||||
self.fs2db.reset_browsercord(self.module, model,
|
||||
[r.id for r in records])
|
||||
|
||||
def write_records(self, module, model,
|
||||
record, values, old_values, fs_id, mdata_id, *args):
|
||||
args = (record, values, old_values, fs_id, mdata_id) + args
|
||||
Model = self.pool.get(model)
|
||||
|
||||
actions = iter(args)
|
||||
to_update = []
|
||||
for record, values, _, _, _ in zip(*((actions,) * 5)):
|
||||
if values:
|
||||
to_update += [[record], values]
|
||||
# if there is values to update:
|
||||
if to_update:
|
||||
# write the values in the db:
|
||||
with Transaction().set_context(
|
||||
module=module, language='en_US'):
|
||||
Model.write(*to_update)
|
||||
self.fs2db.reset_browsercord(
|
||||
module, Model.__name__, sum(to_update[::2], []))
|
||||
|
||||
actions = iter(to_update)
|
||||
for records, values in zip(actions, actions):
|
||||
record, = records
|
||||
# re-read it: this ensure that we store the real value
|
||||
# in the model_data table:
|
||||
record = self.fs2db.get_browserecord(
|
||||
module, Model.__name__, record.id)
|
||||
if not record:
|
||||
record = Model(record.id)
|
||||
for key in values:
|
||||
values[key] = self._clean_value(key, record)
|
||||
|
||||
actions = iter(args)
|
||||
for record, values, old_values, fs_id, mdata_id in zip(
|
||||
*((actions,) * 5)):
|
||||
if module != self.module:
|
||||
temp_values = old_values.copy()
|
||||
temp_values.update(values)
|
||||
values = temp_values
|
||||
|
||||
if values != old_values:
|
||||
self.grouped_model_data.extend(([self.ModelData(mdata_id)], {
|
||||
'fs_id': fs_id,
|
||||
'model': model,
|
||||
'module': module,
|
||||
'db_id': record.id,
|
||||
'values': str(values),
|
||||
'date_update': datetime.datetime.now(),
|
||||
}))
|
||||
|
||||
# reset_browsercord to keep cache memory low
|
||||
self.fs2db.reset_browsercord(module, Model.__name__, args[::5])
|
||||
|
||||
|
||||
def post_import(pool, module, to_delete):
|
||||
"""
|
||||
|
||||
+22
-14
@@ -56,9 +56,9 @@ class Action(ModelSQL, ModelView):
|
||||
return True
|
||||
|
||||
@classmethod
|
||||
def write(cls, actions, values):
|
||||
def write(cls, actions, values, *args):
|
||||
pool = Pool()
|
||||
super(Action, cls).write(actions, values)
|
||||
super(Action, cls).write(actions, values, *args)
|
||||
pool.get('ir.action.keyword')._get_keyword_cache.clear()
|
||||
|
||||
@classmethod
|
||||
@@ -194,9 +194,12 @@ class ActionKeyword(ModelSQL, ModelView):
|
||||
return super(ActionKeyword, cls).create(new_vlist)
|
||||
|
||||
@classmethod
|
||||
def write(cls, keywords, vals):
|
||||
vals = cls._convert_vals(vals)
|
||||
super(ActionKeyword, cls).write(keywords, vals)
|
||||
def write(cls, keywords, values, *args):
|
||||
actions = iter((keywords, values) + args)
|
||||
args = []
|
||||
for keywords, values in zip(actions, actions):
|
||||
args.extend((keywords, cls._convert_vals(values)))
|
||||
super(ActionKeyword, cls).write(*args)
|
||||
ModelView._fields_view_get_cache.clear()
|
||||
ModelView._view_toolbar_get_cache.clear()
|
||||
cls._get_keyword_cache.clear()
|
||||
@@ -329,10 +332,10 @@ class ActionMixin(ModelSQL):
|
||||
return new_records
|
||||
|
||||
@classmethod
|
||||
def write(cls, records, values):
|
||||
def write(cls, records, values, *args):
|
||||
pool = Pool()
|
||||
ActionKeyword = pool.get('ir.action.keyword')
|
||||
super(ActionMixin, cls).write(records, values)
|
||||
super(ActionMixin, cls).write(records, values, *args)
|
||||
ActionKeyword._get_keyword_cache.clear()
|
||||
|
||||
@classmethod
|
||||
@@ -645,13 +648,18 @@ class ActionReport(ActionMixin, ModelSQL, ModelView):
|
||||
return new_reports
|
||||
|
||||
@classmethod
|
||||
def write(cls, reports, vals):
|
||||
def write(cls, reports, values, *args):
|
||||
context = Transaction().context
|
||||
if 'module' in context:
|
||||
vals = vals.copy()
|
||||
vals['module'] = context['module']
|
||||
|
||||
super(ActionReport, cls).write(reports, vals)
|
||||
actions = iter((reports, values) + args)
|
||||
args = []
|
||||
for reports, values in zip(actions, actions):
|
||||
values = values.copy()
|
||||
values['module'] = context['module']
|
||||
args.extend((reports, values))
|
||||
reports, values = args[:2]
|
||||
args = args[2:]
|
||||
super(ActionReport, cls).write(reports, values, *args)
|
||||
|
||||
|
||||
class ActionActWindow(ActionMixin, ModelSQL, ModelView):
|
||||
@@ -908,9 +916,9 @@ class ActionActWindowView(ModelSQL, ModelView):
|
||||
return windows
|
||||
|
||||
@classmethod
|
||||
def write(cls, windows, values):
|
||||
def write(cls, windows, values, *args):
|
||||
pool = Pool()
|
||||
super(ActionActWindowView, cls).write(windows, values)
|
||||
super(ActionActWindowView, cls).write(windows, values, *args)
|
||||
pool.get('ir.action.keyword')._get_keyword_cache.clear()
|
||||
|
||||
@classmethod
|
||||
|
||||
@@ -231,10 +231,14 @@ class Attachment(ModelSQL, ModelView):
|
||||
super(Attachment, cls).delete(attachments)
|
||||
|
||||
@classmethod
|
||||
def write(cls, attachments, vals):
|
||||
cls.check_access([a.id for a in attachments], mode='write')
|
||||
super(Attachment, cls).write(attachments, vals)
|
||||
cls.check_access(attachments, mode='write')
|
||||
def write(cls, attachments, values, *args):
|
||||
all_attachments = []
|
||||
actions = iter((attachments, values) + args)
|
||||
for records, _ in zip(actions, actions):
|
||||
all_attachments += records
|
||||
cls.check_access([a.id for a in all_attachments], mode='write')
|
||||
super(Attachment, cls).write(attachments, values, *args)
|
||||
cls.check_access(all_attachments, mode='write')
|
||||
|
||||
@classmethod
|
||||
def create(cls, vlist):
|
||||
|
||||
+2
-2
@@ -213,12 +213,12 @@ class Lang(ModelSQL, ModelView):
|
||||
return languages
|
||||
|
||||
@classmethod
|
||||
def write(cls, langs, vals):
|
||||
def write(cls, langs, values, *args):
|
||||
pool = Pool()
|
||||
Translation = pool.get('ir.translation')
|
||||
# Clear cache
|
||||
cls._lang_cache.clear()
|
||||
super(Lang, cls).write(langs, vals)
|
||||
super(Lang, cls).write(langs, values, *args)
|
||||
Translation._get_language_cache.clear()
|
||||
|
||||
@classmethod
|
||||
|
||||
+10
-10
@@ -139,10 +139,10 @@ class Model(ModelSQL, ModelView):
|
||||
return res
|
||||
|
||||
@classmethod
|
||||
def write(cls, models, vals):
|
||||
def write(cls, models, values, *args):
|
||||
pool = Pool()
|
||||
Property = pool.get('ir.property')
|
||||
super(Model, cls).write(models, vals)
|
||||
super(Model, cls).write(models, values, *args)
|
||||
# Restart the cache of models_get
|
||||
Property._models_get_cache.clear()
|
||||
|
||||
@@ -527,8 +527,8 @@ class ModelAccess(ModelSQL, ModelView):
|
||||
return True
|
||||
|
||||
@classmethod
|
||||
def write(cls, accesses, vals):
|
||||
super(ModelAccess, cls).write(accesses, vals)
|
||||
def write(cls, accesses, values, *args):
|
||||
super(ModelAccess, cls).write(accesses, values, *args)
|
||||
# Restart the cache
|
||||
cls._get_access_cache.clear()
|
||||
ModelView._fields_view_get_cache.clear()
|
||||
@@ -681,8 +681,8 @@ class ModelFieldAccess(ModelSQL, ModelView):
|
||||
return True
|
||||
|
||||
@classmethod
|
||||
def write(cls, field_accesses, vals):
|
||||
super(ModelFieldAccess, cls).write(field_accesses, vals)
|
||||
def write(cls, field_accesses, values, *args):
|
||||
super(ModelFieldAccess, cls).write(field_accesses, values, *args)
|
||||
# Restart the cache
|
||||
cls._get_access_cache.clear()
|
||||
ModelView._fields_view_get_cache.clear()
|
||||
@@ -730,8 +730,8 @@ class ModelButton(ModelSQL, ModelView):
|
||||
return result
|
||||
|
||||
@classmethod
|
||||
def write(cls, buttons, values):
|
||||
super(ModelButton, cls).write(buttons, values)
|
||||
def write(cls, buttons, values, *args):
|
||||
super(ModelButton, cls).write(buttons, values, *args)
|
||||
# Restart the cache for get_groups
|
||||
cls._groups_cache.clear()
|
||||
|
||||
@@ -813,8 +813,8 @@ class ModelData(ModelSQL, ModelView):
|
||||
return False
|
||||
|
||||
@classmethod
|
||||
def write(cls, data, values):
|
||||
super(ModelData, cls).write(data, values)
|
||||
def write(cls, data, values, *args):
|
||||
super(ModelData, cls).write(data, values, *args)
|
||||
# Restart the cache for get_id
|
||||
cls._get_id_cache.clear()
|
||||
|
||||
|
||||
+4
-4
@@ -86,8 +86,8 @@ class RuleGroup(ModelSQL, ModelView):
|
||||
return res
|
||||
|
||||
@classmethod
|
||||
def write(cls, groups, vals):
|
||||
super(RuleGroup, cls).write(groups, vals)
|
||||
def write(cls, groups, vals, *args):
|
||||
super(RuleGroup, cls).write(groups, vals, *args)
|
||||
# Restart the cache on the domain_get method of ir.rule
|
||||
Pool().get('ir.rule')._domain_get_cache.clear()
|
||||
|
||||
@@ -276,7 +276,7 @@ class Rule(ModelSQL, ModelView):
|
||||
return res
|
||||
|
||||
@classmethod
|
||||
def write(cls, rules, vals):
|
||||
super(Rule, cls).write(rules, vals)
|
||||
def write(cls, rules, vals, *args):
|
||||
super(Rule, cls).write(rules, vals, *args)
|
||||
# Restart the cache on the domain_get method
|
||||
cls._domain_get_cache.clear()
|
||||
@@ -184,12 +184,13 @@ class Sequence(ModelSQL, ModelView):
|
||||
return sequences
|
||||
|
||||
@classmethod
|
||||
def write(cls, sequences, values):
|
||||
result = super(Sequence, cls).write(sequences, values)
|
||||
def write(cls, sequences, values, *args):
|
||||
super(Sequence, cls).write(sequences, values, *args)
|
||||
if sql_sequence and not cls._strict:
|
||||
for sequence in sequences:
|
||||
sequence.update_sql_sequence(values.get('number_next'))
|
||||
return result
|
||||
actions = iter((sequences, values) + args)
|
||||
for sequences, values in zip(actions, actions):
|
||||
for sequence in sequences:
|
||||
sequence.update_sql_sequence(values.get('number_next'))
|
||||
|
||||
@classmethod
|
||||
def delete(cls, sequences):
|
||||
|
||||
@@ -731,13 +731,17 @@ class Translation(ModelSQL, ModelView):
|
||||
return super(Translation, cls).create(vlist)
|
||||
|
||||
@classmethod
|
||||
def write(cls, translations, vals):
|
||||
def write(cls, translations, values, *args):
|
||||
cls._translation_cache.clear()
|
||||
ModelView._fields_view_get_cache.clear()
|
||||
if 'src' in vals:
|
||||
vals = vals.copy()
|
||||
vals['src_md5'] = cls.get_src_md5(vals.get('src'))
|
||||
return super(Translation, cls).write(translations, vals)
|
||||
actions = iter((translations, values) + args)
|
||||
args = []
|
||||
for translations, values in zip(actions, actions):
|
||||
if 'src' in values:
|
||||
values = values.copy()
|
||||
values['src_md5'] = cls.get_src_md5(values.get('src'))
|
||||
args.extend((translations, values))
|
||||
return super(Translation, cls).write(*args)
|
||||
|
||||
@classmethod
|
||||
def extra_model_data(cls, model_data):
|
||||
|
||||
@@ -270,11 +270,10 @@ class Trigger(ModelSQL, ModelView):
|
||||
return res
|
||||
|
||||
@classmethod
|
||||
def write(cls, ids, values):
|
||||
res = super(Trigger, cls).write(ids, values)
|
||||
def write(cls, triggers, values, *args):
|
||||
super(Trigger, cls).write(triggers, values, *args)
|
||||
# Restart the cache on the get_triggers method of ir.trigger
|
||||
cls._get_triggers_cache.clear()
|
||||
return res
|
||||
|
||||
@classmethod
|
||||
def delete(cls, records):
|
||||
|
||||
@@ -196,8 +196,8 @@ class View(ModelSQL, ModelView):
|
||||
return views
|
||||
|
||||
@classmethod
|
||||
def write(cls, views, vals):
|
||||
super(View, cls).write(views, vals)
|
||||
def write(cls, views, values, *args):
|
||||
super(View, cls).write(views, values, *args)
|
||||
# Restart the cache
|
||||
ModelView._fields_view_get_cache.clear()
|
||||
|
||||
@@ -260,8 +260,8 @@ class ViewTreeWidth(ModelSQL, ModelView):
|
||||
return res
|
||||
|
||||
@classmethod
|
||||
def write(cls, records, vals):
|
||||
super(ViewTreeWidth, cls).write(records, vals)
|
||||
def write(cls, records, values, *args):
|
||||
super(ViewTreeWidth, cls).write(records, values, *args)
|
||||
ModelView._fields_view_get_cache.clear()
|
||||
|
||||
@classmethod
|
||||
|
||||
@@ -101,7 +101,7 @@ class Many2Many(Field):
|
||||
|
||||
values: A list of tuples:
|
||||
(``create``, ``[{<field name>: value}, ...]``),
|
||||
(``write``, ``<ids>``, ``{<field name>: value}``),
|
||||
(``write``, [``<ids>``, ``{<field name>: value}``, ...]),
|
||||
(``delete``, ``<ids>``),
|
||||
(``delete_all``),
|
||||
(``unlink``, ``<ids>``),
|
||||
@@ -142,7 +142,9 @@ class Many2Many(Field):
|
||||
if to_create:
|
||||
Relation.create(to_create)
|
||||
elif act[0] == 'write':
|
||||
Target.write(Target.browse(act[1]), act[2])
|
||||
actions = iter(act[1:])
|
||||
Target.write(*sum(((Target.browse(ids), values)
|
||||
for ids, values in zip(actions, actions)), ()))
|
||||
elif act[0] == 'delete':
|
||||
Target.delete(Target.browse(act[1]))
|
||||
elif act[0] == 'delete_all':
|
||||
|
||||
@@ -107,7 +107,7 @@ class One2Many(Field):
|
||||
Set the values.
|
||||
values: A list of tuples:
|
||||
(``create``, ``[{<field name>: value}, ...]``),
|
||||
(``write``, ``<ids>``, ``{<field name>: value}``),
|
||||
(``write``, [``<ids>``, ``{<field name>: value}``, ...]),
|
||||
(``delete``, ``<ids>``),
|
||||
(``delete_all``),
|
||||
(``unlink``, ``<ids>``),
|
||||
@@ -146,7 +146,9 @@ class One2Many(Field):
|
||||
if to_create:
|
||||
Target.create(to_create)
|
||||
elif act[0] == 'write':
|
||||
Target.write(Target.browse(act[1]), act[2])
|
||||
actions = iter(act[1:])
|
||||
Target.write(*sum(((Target.browse(ids), values)
|
||||
for ids, values in zip(actions, actions)), ()))
|
||||
elif act[0] == 'delete':
|
||||
Target.delete(Target.browse(act[1]))
|
||||
elif act[0] == 'delete_all':
|
||||
@@ -169,10 +171,14 @@ class One2Many(Field):
|
||||
target_ids = map(int, act[1])
|
||||
if not target_ids:
|
||||
continue
|
||||
targets = Target.browse(target_ids)
|
||||
actions = []
|
||||
for record_id in ids:
|
||||
Target.write(Target.browse(target_ids), {
|
||||
actions.append(targets)
|
||||
actions.append({
|
||||
self.field: field_value(record_id),
|
||||
})
|
||||
Target.write(*actions)
|
||||
elif act[0] == 'unlink_all':
|
||||
targets = Target.search([
|
||||
search_clause(ids),
|
||||
@@ -185,18 +191,22 @@ class One2Many(Field):
|
||||
target_ids = [-1]
|
||||
else:
|
||||
target_ids = map(int, act[1])
|
||||
actions = []
|
||||
for record_id in ids:
|
||||
targets = Target.search([
|
||||
search_clause([record_id]),
|
||||
('id', 'not in', target_ids),
|
||||
])
|
||||
Target.write(targets, {
|
||||
actions.append(targets)
|
||||
actions.append({
|
||||
self.field: None,
|
||||
})
|
||||
if act[1]:
|
||||
Target.write(Target.browse(target_ids), {
|
||||
actions.append(Target.browse(target_ids))
|
||||
actions.append({
|
||||
self.field: field_value(record_id),
|
||||
})
|
||||
Target.write(*actions)
|
||||
elif act[0] == 'copy':
|
||||
copy_ids = map(int, act[1])
|
||||
|
||||
|
||||
@@ -49,11 +49,15 @@ class ModelSingleton(ModelStorage):
|
||||
return res
|
||||
|
||||
@classmethod
|
||||
def write(cls, records, values):
|
||||
def write(cls, records, values, *args):
|
||||
singleton = cls.get_singleton()
|
||||
if not singleton:
|
||||
return cls.create([values])
|
||||
return super(ModelSingleton, cls).write([singleton], values)
|
||||
singleton, = cls.create([values])
|
||||
actions = (records, values) + args
|
||||
args = []
|
||||
for values in actions[1:None:2]:
|
||||
args.extend(([singleton], values))
|
||||
return super(ModelSingleton, cls).write(*args)
|
||||
|
||||
@classmethod
|
||||
def delete(cls, records):
|
||||
|
||||
+67
-64
@@ -629,94 +629,97 @@ class ModelSQL(ModelStorage):
|
||||
return result
|
||||
|
||||
@classmethod
|
||||
def write(cls, records, values):
|
||||
def write(cls, records, values, *args):
|
||||
DatabaseIntegrityError = backend.get('DatabaseIntegrityError')
|
||||
transaction = Transaction()
|
||||
cursor = transaction.cursor
|
||||
pool = Pool()
|
||||
Translation = pool.get('ir.translation')
|
||||
Config = pool.get('ir.configuration')
|
||||
ids = map(int, records)
|
||||
in_max = cursor.IN_MAX
|
||||
|
||||
assert not len(args) % 2
|
||||
all_records = sum(((records, values) + args)[0:None:2], [])
|
||||
all_ids = [r.id for r in all_records]
|
||||
|
||||
# Call before cursor cache cleaning
|
||||
trigger_eligibles = cls.trigger_write_get_eligibles(records)
|
||||
|
||||
super(ModelSQL, cls).write(records, values)
|
||||
|
||||
if not records:
|
||||
return
|
||||
super(ModelSQL, cls).write(records, values, *args)
|
||||
|
||||
if cls.table_query():
|
||||
return
|
||||
table = cls.__table__()
|
||||
|
||||
values = values.copy()
|
||||
cls.__check_timestamp(all_ids)
|
||||
|
||||
cls.__check_timestamp(ids)
|
||||
actions = iter((records, values) + args)
|
||||
for records, values in zip(actions, actions):
|
||||
ids = [r.id for r in records]
|
||||
values = values.copy()
|
||||
|
||||
# Clean values
|
||||
for key in ('create_uid', 'create_date',
|
||||
'write_uid', 'write_date', 'id'):
|
||||
if key in values:
|
||||
del values[key]
|
||||
# Clean values
|
||||
for key in ('create_uid', 'create_date',
|
||||
'write_uid', 'write_date', 'id'):
|
||||
if key in values:
|
||||
del values[key]
|
||||
|
||||
columns = [table.write_uid, table.write_date]
|
||||
update_values = [transaction.user, Now()]
|
||||
store_translation = Transaction().language == Config.get_language()
|
||||
for fname, value in values.iteritems():
|
||||
field = cls._fields[fname]
|
||||
if not hasattr(field, 'set'):
|
||||
if not getattr(field, 'translate', False) or store_translation:
|
||||
columns.append(Column(table, fname))
|
||||
update_values.append(field.sql_format(value))
|
||||
columns = [table.write_uid, table.write_date]
|
||||
update_values = [transaction.user, Now()]
|
||||
store_translation = Transaction().language == Config.get_language()
|
||||
for fname, value in values.iteritems():
|
||||
field = cls._fields[fname]
|
||||
if not hasattr(field, 'set'):
|
||||
if (not getattr(field, 'translate', False)
|
||||
or store_translation):
|
||||
columns.append(Column(table, fname))
|
||||
update_values.append(field.sql_format(value))
|
||||
|
||||
domain = pool.get('ir.rule').domain_get(cls.__name__, mode='write')
|
||||
for i in range(0, len(ids), in_max):
|
||||
sub_ids = ids[i:i + in_max]
|
||||
red_sql = reduce_ids(table.id, sub_ids)
|
||||
where = red_sql
|
||||
if domain:
|
||||
where &= table.id.in_(domain)
|
||||
cursor.execute(*table.select(table.id, where=where))
|
||||
rowcount = cursor.rowcount
|
||||
if rowcount == -1 or rowcount is None:
|
||||
rowcount = len(cursor.fetchall())
|
||||
if not rowcount == len({}.fromkeys(sub_ids)):
|
||||
domain = pool.get('ir.rule').domain_get(cls.__name__, mode='write')
|
||||
for i in range(0, len(ids), in_max):
|
||||
sub_ids = ids[i:i + in_max]
|
||||
red_sql = reduce_ids(table.id, sub_ids)
|
||||
where = red_sql
|
||||
if domain:
|
||||
cursor.execute(*table.select(table.id, where=red_sql))
|
||||
rowcount = cursor.rowcount
|
||||
if rowcount == -1 or rowcount is None:
|
||||
rowcount = len(cursor.fetchall())
|
||||
if rowcount == len({}.fromkeys(sub_ids)):
|
||||
cls.raise_user_error('access_error', cls.__name__)
|
||||
cls.raise_user_error('write_error', cls.__name__)
|
||||
try:
|
||||
cursor.execute(*table.update(columns, update_values,
|
||||
where=red_sql))
|
||||
except DatabaseIntegrityError, exception:
|
||||
with contextlib.nested(Transaction().new_cursor(),
|
||||
Transaction().set_user(0)):
|
||||
cls.__raise_integrity_error(exception, values,
|
||||
values.keys())
|
||||
raise
|
||||
where &= table.id.in_(domain)
|
||||
cursor.execute(*table.select(table.id, where=where))
|
||||
rowcount = cursor.rowcount
|
||||
if rowcount == -1 or rowcount is None:
|
||||
rowcount = len(cursor.fetchall())
|
||||
if not rowcount == len({}.fromkeys(sub_ids)):
|
||||
if domain:
|
||||
cursor.execute(*table.select(table.id, where=red_sql))
|
||||
rowcount = cursor.rowcount
|
||||
if rowcount == -1 or rowcount is None:
|
||||
rowcount = len(cursor.fetchall())
|
||||
if rowcount == len({}.fromkeys(sub_ids)):
|
||||
cls.raise_user_error('access_error', cls.__name__)
|
||||
cls.raise_user_error('write_error', cls.__name__)
|
||||
try:
|
||||
cursor.execute(*table.update(columns, update_values,
|
||||
where=red_sql))
|
||||
except DatabaseIntegrityError, exception:
|
||||
with contextlib.nested(Transaction().new_cursor(),
|
||||
Transaction().set_user(0)):
|
||||
cls.__raise_integrity_error(exception, values,
|
||||
values.keys())
|
||||
raise
|
||||
|
||||
for fname, value in values.iteritems():
|
||||
field = cls._fields[fname]
|
||||
if (getattr(field, 'translate', False)
|
||||
and not hasattr(field, 'set')):
|
||||
Translation.set_ids(
|
||||
'%s,%s' % (cls.__name__, fname), 'model',
|
||||
transaction.language, ids, [value] * len(ids))
|
||||
if hasattr(field, 'set'):
|
||||
field.set(ids, cls, fname, value)
|
||||
for fname, value in values.iteritems():
|
||||
field = cls._fields[fname]
|
||||
if (getattr(field, 'translate', False)
|
||||
and not hasattr(field, 'set')):
|
||||
Translation.set_ids(
|
||||
'%s,%s' % (cls.__name__, fname), 'model',
|
||||
transaction.language, ids, [value] * len(ids))
|
||||
if hasattr(field, 'set'):
|
||||
field.set(ids, cls, fname, value)
|
||||
|
||||
cls.__insert_history(ids)
|
||||
cls._validate(records)
|
||||
|
||||
field_names = cls._fields.keys()
|
||||
cls._update_mptt(field_names, [ids] * len(field_names), values)
|
||||
field_names = cls._fields.keys()
|
||||
cls._update_mptt(field_names, [ids] * len(field_names), values)
|
||||
|
||||
cls.__insert_history(all_ids)
|
||||
cls._validate(all_records)
|
||||
cls.trigger_write(trigger_eligibles)
|
||||
|
||||
@classmethod
|
||||
|
||||
@@ -53,7 +53,8 @@ class ModelStorage(Model):
|
||||
'create': RPC(readonly=False,
|
||||
result=lambda r: map(int, r)),
|
||||
'read': RPC(),
|
||||
'write': RPC(readonly=False, instantiate=0),
|
||||
'write': RPC(readonly=False,
|
||||
instantiate=slice(0, None, 2)),
|
||||
'delete': RPC(readonly=False, instantiate=0),
|
||||
'copy': RPC(readonly=False, instantiate=0,
|
||||
result=lambda r: map(int, r)),
|
||||
@@ -126,7 +127,7 @@ class ModelStorage(Model):
|
||||
return []
|
||||
|
||||
@classmethod
|
||||
def write(cls, records, values):
|
||||
def write(cls, records, values, *args):
|
||||
'''
|
||||
Write values on records.
|
||||
'''
|
||||
@@ -137,15 +138,21 @@ class ModelStorage(Model):
|
||||
ModelAccess.check(cls.__name__, 'write')
|
||||
ModelFieldAccess.check(cls.__name__,
|
||||
[x for x in values if x in cls._fields], 'write')
|
||||
if not cls.check_xml_record(records, values):
|
||||
cls.raise_user_error('write_xml_record',
|
||||
error_description='xml_record_desc')
|
||||
|
||||
assert not len(args) % 2
|
||||
actions = iter((records, values) + args)
|
||||
all_records = []
|
||||
for records, values in zip(actions, actions):
|
||||
if not cls.check_xml_record(records, values):
|
||||
cls.raise_user_error('write_xml_record',
|
||||
error_description='xml_record_desc')
|
||||
all_records += records
|
||||
|
||||
# Increase transaction counter
|
||||
Transaction().counter += 1
|
||||
|
||||
# Clean local cache
|
||||
for record in records:
|
||||
for record in all_records:
|
||||
local_cache = record._local_cache.get(record.id)
|
||||
if local_cache:
|
||||
local_cache.clear()
|
||||
@@ -153,7 +160,7 @@ class ModelStorage(Model):
|
||||
# Clean cursor cache
|
||||
for cache in Transaction().cursor.cache.itervalues():
|
||||
if cls.__name__ in cache:
|
||||
for record in records:
|
||||
for record in all_records:
|
||||
if record.id in cache[cls.__name__]:
|
||||
cache[cls.__name__][record.id].clear()
|
||||
|
||||
|
||||
@@ -89,8 +89,8 @@ class Group(ModelSQL, ModelView):
|
||||
return res
|
||||
|
||||
@classmethod
|
||||
def write(cls, groups, vals):
|
||||
super(Group, cls).write(groups, vals)
|
||||
def write(cls, groups, values, *args):
|
||||
super(Group, cls).write(groups, values, *args)
|
||||
pool = Pool()
|
||||
# Restart the cache on the domain_get method
|
||||
pool.get('ir.rule')._domain_get_cache.clear()
|
||||
|
||||
+19
-15
@@ -44,8 +44,8 @@ class UIMenuGroup(ModelSQL):
|
||||
return res
|
||||
|
||||
@classmethod
|
||||
def write(cls, records, vals):
|
||||
super(UIMenuGroup, cls).write(records, vals)
|
||||
def write(cls, records, values, *args):
|
||||
super(UIMenuGroup, cls).write(records, values, *args)
|
||||
# Restart the cache on the domain_get method
|
||||
Pool().get('ir.rule')._domain_get_cache.clear()
|
||||
|
||||
@@ -91,12 +91,16 @@ class ActionGroup(ModelSQL):
|
||||
return res
|
||||
|
||||
@classmethod
|
||||
def write(cls, records, vals):
|
||||
def write(cls, records, values, *args):
|
||||
Action = Pool().get('ir.action')
|
||||
if vals.get('action'):
|
||||
vals = vals.copy()
|
||||
vals['action'] = Action.get_action_id(vals['action'])
|
||||
super(ActionGroup, cls).write(records, vals)
|
||||
actions = iter((records, values) + args)
|
||||
args = []
|
||||
for records, values in zip(actions, actions):
|
||||
if values.get('action'):
|
||||
values = values.copy()
|
||||
values['action'] = Action.get_action_id(values['action'])
|
||||
args.extend((records, values))
|
||||
super(ActionGroup, cls).write(*args)
|
||||
# Restart the cache on the domain_get method
|
||||
Pool().get('ir.rule')._domain_get_cache.clear()
|
||||
|
||||
@@ -153,9 +157,9 @@ class ModelButtonGroup(ModelSQL):
|
||||
return result
|
||||
|
||||
@classmethod
|
||||
def write(cls, records, values):
|
||||
def write(cls, records, values, *args):
|
||||
pool = Pool()
|
||||
super(ModelButtonGroup, cls).write(records, values)
|
||||
super(ModelButtonGroup, cls).write(records, values, *args)
|
||||
# Restart the cache for get_groups
|
||||
pool.get('ir.model.button')._groups_cache.clear()
|
||||
|
||||
@@ -219,8 +223,8 @@ class Lang:
|
||||
__name__ = 'ir.lang'
|
||||
|
||||
@classmethod
|
||||
def write(cls, langs, vals):
|
||||
super(Lang, cls).write(langs, vals)
|
||||
def write(cls, langs, values, *args):
|
||||
super(Lang, cls).write(langs, values, *args)
|
||||
# Restart the cache for get_preferences
|
||||
Pool().get('res.user')._get_preferences_cache.clear()
|
||||
|
||||
@@ -256,9 +260,9 @@ class SequenceTypeGroup(ModelSQL):
|
||||
return res
|
||||
|
||||
@classmethod
|
||||
def write(cls, records, vals):
|
||||
def write(cls, records, values, *args):
|
||||
Rule = Pool().get('ir.rule')
|
||||
super(SequenceTypeGroup, cls).write(records, vals)
|
||||
super(SequenceTypeGroup, cls).write(records, values, *args)
|
||||
# Restart the cache on the domain_get method
|
||||
Rule._domain_get_cache.clear()
|
||||
|
||||
@@ -314,10 +318,10 @@ class ModuleConfigWizardItem:
|
||||
return result
|
||||
|
||||
@classmethod
|
||||
def write(cls, items, values):
|
||||
def write(cls, items, values, *args):
|
||||
pool = Pool()
|
||||
User = pool.get('res.user')
|
||||
super(ModuleConfigWizardItem, cls).write(items, values)
|
||||
super(ModuleConfigWizardItem, cls).write(items, values, *args)
|
||||
# Restart the cache for get_preferences
|
||||
User._get_preferences_cache.clear()
|
||||
|
||||
|
||||
+15
-7
@@ -211,13 +211,18 @@ class User(ModelSQL, ModelView):
|
||||
return res
|
||||
|
||||
@classmethod
|
||||
def write(cls, users, vals):
|
||||
vals = cls._convert_vals(vals)
|
||||
super(User, cls).write(users, vals)
|
||||
def write(cls, users, values, *args):
|
||||
actions = iter((users, values) + args)
|
||||
all_users = []
|
||||
args = []
|
||||
for users, values in zip(actions, actions):
|
||||
all_users += users
|
||||
args.extend((users, cls._convert_vals(values)))
|
||||
super(User, cls).write(*args)
|
||||
# Clean cursor cache as it could be filled by domain_get
|
||||
for cache in Transaction().cursor.cache.itervalues():
|
||||
if cls.__name__ in cache:
|
||||
for user in users:
|
||||
for user in all_users:
|
||||
if user.id in cache[cls.__name__]:
|
||||
cache[cls.__name__][user.id].clear()
|
||||
# Restart the cache for domain_get method
|
||||
@@ -532,9 +537,12 @@ class UserAction(ModelSQL):
|
||||
return super(UserAction, cls).create(vlist)
|
||||
|
||||
@classmethod
|
||||
def write(cls, records, values):
|
||||
values = cls._convert_values(values)
|
||||
super(UserAction, cls).write(records, values)
|
||||
def write(cls, records, values, *args):
|
||||
actions = iter((records, values) + args)
|
||||
args = []
|
||||
for records, values in zip(actions, actions):
|
||||
args.extend((records, cls._convert_values(values)))
|
||||
super(UserAction, cls).write(*args)
|
||||
|
||||
|
||||
class UserGroup(ModelSQL):
|
||||
|
||||
+9
-3
@@ -8,7 +8,7 @@ class RPC(object):
|
||||
'''Define RPC behavior
|
||||
|
||||
readonly: The transaction mode
|
||||
instantiate: The position of the argument to be instanciated
|
||||
instantiate: The position or the slice of the arguments to be instanciated
|
||||
result: The function to transform the result
|
||||
'''
|
||||
|
||||
@@ -41,6 +41,12 @@ class RPC(object):
|
||||
return obj(**data)
|
||||
else:
|
||||
return obj.browse(data)
|
||||
data = args[self.instantiate]
|
||||
args[self.instantiate] = instance(data)
|
||||
if isinstance(self.instantiate, slice):
|
||||
for i, data in enumerate(args[self.instantiate]):
|
||||
start, _, step = self.instantiate.indices(len(args))
|
||||
i = i * step + start
|
||||
args[i] = instance(data)
|
||||
else:
|
||||
data = args[self.instantiate]
|
||||
args[self.instantiate] = instance(data)
|
||||
return args, kwargs, context, timestamp
|
||||
Reference in new issue
Block a user