Add _history_table on ModelSQL to historize change on records
Use _datetime in context to read record value at specific datetime Add datetime_field on Many2One to use a specific _datetime when reading the related record
This commit is contained in:
1 parent
2544147792
commit
3706e76e99
9 files changed
+242
-94
No files matched your search
@@ -1,3 +1,6 @@
|
||||
* Add datetime_field on Many2One to use a specific _datetime when reading the related record
|
||||
* Use _datetime in context to read record value at specific datetime
|
||||
* Add _history_table on ModelSQL to historize change on records
|
||||
* Allow to use related fields (many2one and reference) in read
|
||||
* Use rec_name function field instead of name_get and name_search
|
||||
* Use a new Pool for objects
|
||||
|
||||
@@ -8,7 +8,8 @@ import logging
|
||||
|
||||
class TableHandler(TableHandlerInterface):
|
||||
|
||||
def __init__(self, cursor, table_name, object_name=None, module_name=None):
|
||||
def __init__(self, cursor, table_name, object_name=None, module_name=None,
|
||||
history=False):
|
||||
super(TableHandler, self).__init__(cursor, table_name,
|
||||
object_name=object_name, module_name=module_name)
|
||||
self._columns = {}
|
||||
@@ -19,9 +20,13 @@ class TableHandler(TableHandlerInterface):
|
||||
|
||||
# Create new table if necessary
|
||||
if not self.table_exist(self.cursor, self.table_name):
|
||||
self.cursor.execute('CREATE TABLE "%s" ' \
|
||||
"(id SERIAL NOT NULL, " \
|
||||
"PRIMARY KEY(id))"% self.table_name)
|
||||
if not history:
|
||||
self.cursor.execute('CREATE TABLE "%s" ' \
|
||||
"(id SERIAL NOT NULL, " \
|
||||
"PRIMARY KEY(id))"% self.table_name)
|
||||
else:
|
||||
self.cursor.execute('CREATE TABLE "%s" ' \
|
||||
'(id INTEGER)' % self.table_name)
|
||||
self._update_definitions()
|
||||
|
||||
@staticmethod
|
||||
|
||||
@@ -7,7 +7,8 @@ class TableHandlerInterface(object):
|
||||
Define generic interface to handle database table
|
||||
'''
|
||||
|
||||
def __init__(self, cursor, table_name, object_name=None, module_name=None):
|
||||
def __init__(self, cursor, table_name, object_name=None, module_name=None,
|
||||
history=False):
|
||||
super(TableHandlerInterface, self).__init__()
|
||||
self.cursor = cursor
|
||||
self.table_name = table_name
|
||||
|
||||
+16
-1
@@ -103,6 +103,17 @@ class BrowseRecord(object):
|
||||
# otherwise we fetch only that field
|
||||
else:
|
||||
ffields = [(name, col)]
|
||||
|
||||
# add datetime_field
|
||||
for i, j in ffields:
|
||||
if j._type == 'many2one' and hasattr(j, 'datetime_field') \
|
||||
and j.datetime_field:
|
||||
if j.datetime_field in self._model._columns:
|
||||
col = self._model._columns[j.datetime_field]
|
||||
else:
|
||||
col = self._model._inherit_fields[j.datetime_field][2]
|
||||
ffields.append((j.datetime_field, col))
|
||||
|
||||
ids = [x for x in self._data.keys() \
|
||||
if not self._data[x].has_key(name)]
|
||||
# read the data
|
||||
@@ -121,9 +132,13 @@ class BrowseRecord(object):
|
||||
if not data[i]:
|
||||
data[i] = BrowseRecordNull()
|
||||
else:
|
||||
ctx = self._context
|
||||
if hasattr(j, 'datetime_field') and j.datetime_field:
|
||||
ctx = self._context.copy()
|
||||
ctx['_datetime'] = data[j.datetime_field]
|
||||
data[i] = BrowseRecord(self._cursor, self._user,
|
||||
data[i], model, self._cache,
|
||||
context=self._context)
|
||||
context=ctx)
|
||||
elif j._type in ('one2many', 'many2many') and len(data[i]):
|
||||
data[i] = BrowseRecordList([BrowseRecord(self._cursor,
|
||||
self._user,
|
||||
|
||||
@@ -8,9 +8,10 @@ class Many2One(Field):
|
||||
_type = 'many2one'
|
||||
|
||||
def __init__(self, model_name, string='', left=None, right=None,
|
||||
ondelete='SET NULL', **args):
|
||||
ondelete='SET NULL', datetime_field=None, **args):
|
||||
super(Many2One, self).__init__(string=string, **args)
|
||||
self.model_name = model_name
|
||||
self.left = left
|
||||
self.right = right
|
||||
self.ondelete = ondelete
|
||||
self.datetime_field = datetime_field
|
||||
@@ -26,6 +26,8 @@ class One2Many(Field):
|
||||
for i in model.pool.get(self.model_name).read(cursor, user, ids2,
|
||||
[self.field], context=context):
|
||||
res[i[self.field]].append(i['id'])
|
||||
for val in res.values():
|
||||
val.sort(lambda x, y: cmp(ids2.index(x), ids2.index(y)))
|
||||
return res
|
||||
|
||||
def set(self, cursor, user, record_id, model, name, values, context=None):
|
||||
|
||||
@@ -28,9 +28,9 @@ class Reference(Field):
|
||||
ref_model, ref_id = res[i].split(',', 1)
|
||||
if not ref_model:
|
||||
continue
|
||||
ref_obj = model.pool.get(ref_model)
|
||||
if not ref_obj:
|
||||
if ref_model not in model.pool.object_name_list():
|
||||
continue
|
||||
ref_obj = model.pool.get(ref_model)
|
||||
try:
|
||||
ref_id = eval(ref_id)
|
||||
except:
|
||||
|
||||
+205
-84
@@ -17,6 +17,7 @@ class ModelSQL(ModelStorage):
|
||||
_sequence = None
|
||||
_sql = ''
|
||||
_auto = True #XXX to remove when module will use the new models
|
||||
_history_table = None
|
||||
|
||||
def __init__(self):
|
||||
super(ModelSQL, self).__init__()
|
||||
@@ -38,6 +39,9 @@ class ModelSQL(ModelStorage):
|
||||
|
||||
# create/update table in the database
|
||||
table = TableHandler(cursor, self._table, self._name, module_name)
|
||||
if self._history_table:
|
||||
history_table = TableHandler(cursor, self._history_table, None,
|
||||
module_name, history=True)
|
||||
datetime_field = FIELDS['datetime']
|
||||
integer_field = FIELDS['integer']
|
||||
logs = (
|
||||
@@ -55,6 +59,24 @@ class ModelSQL(ModelStorage):
|
||||
for log in logs:
|
||||
table.add_raw_column(log[0], log[1], (log[2], log[3]),
|
||||
default_fun=log[4], migrate=False)
|
||||
if self._history_table:
|
||||
history_logs = (
|
||||
('create_date', datetime_field.sql_type(None),
|
||||
datetime_field.symbol_c, datetime_field.symbol_f),
|
||||
('write_date', datetime_field.sql_type(None),
|
||||
datetime_field.symbol_c, datetime_field.symbol_f),
|
||||
('create_uid', (integer_field.sql_type(None)[0],
|
||||
'INTEGER REFERENCES res_user ON DELETE SET NULL',),
|
||||
integer_field.symbol_c, integer_field.symbol_f),
|
||||
('write_uid', (integer_field.sql_type(None)[0],
|
||||
'INTEGER REFERENCES res_user ON DELETE SET NULL'),
|
||||
integer_field.symbol_c, integer_field.symbol_f),
|
||||
)
|
||||
for log in history_logs:
|
||||
history_table.add_raw_column(log[0], log[1], (log[2], log[3]),
|
||||
migrate=False)
|
||||
history_table.index_action('id', action='add')
|
||||
|
||||
for field_name, field in self._columns.iteritems():
|
||||
default_fun = None
|
||||
if field_name in (
|
||||
@@ -88,6 +110,11 @@ class ModelSQL(ModelStorage):
|
||||
(FIELDS[field._type].symbol_c,
|
||||
FIELDS[field._type].symbol_f), default_fun,
|
||||
hasattr(field, 'size') and field.size or None)
|
||||
if self._history_table:
|
||||
history_table.add_raw_column(field_name,
|
||||
FIELDS[field._type].sql_type(field),
|
||||
(FIELDS[field._type].symbol_c,
|
||||
FIELDS[field._type].symbol_f))
|
||||
|
||||
if isinstance(field, (fields.Integer, fields.Float)):
|
||||
table.db_default(field_name, 0)
|
||||
@@ -110,6 +137,7 @@ class ModelSQL(ModelStorage):
|
||||
field_name, action=required and 'add' or 'remove')
|
||||
|
||||
elif isinstance(field, fields.Many2Many):
|
||||
#TODO handle history
|
||||
if field.model_name in ('res.user', 'res.group'):
|
||||
ref = field.model_name.replace('.','_')
|
||||
else:
|
||||
@@ -130,6 +158,20 @@ class ModelSQL(ModelStorage):
|
||||
for ident, constraint, msg in self._sql_constraints:
|
||||
table.add_constraint(ident, constraint)
|
||||
|
||||
if self._history_table:
|
||||
cursor.execute('SELECT id FROM "' + self._table + '"')
|
||||
if cursor.rowcount:
|
||||
cursor.execute('SELECT id FROM "' + self._history_table + '"')
|
||||
if not cursor.rowcount:
|
||||
columns = ['"' + str(x) + '"' for x in self._columns
|
||||
if not hasattr(self._columns[x], 'set')]
|
||||
cursor.execute('INSERT INTO "' + self._history_table + '" '\
|
||||
'(' + ','.join(columns) + ') ' \
|
||||
'SELECT ' + ','.join(columns) + \
|
||||
' FROM "' + self._table + '"')
|
||||
cursor.execute('UPDATE "' + self._history_table + '" ' \
|
||||
'SET write_date = NULL')
|
||||
|
||||
def _get_error_messages(self):
|
||||
res = super(ModelSQL, self)._get_error_messages()
|
||||
res += self._sql_error_messages.values()
|
||||
@@ -253,6 +295,13 @@ class ModelSQL(ModelStorage):
|
||||
self._columns[field].set(cursor, user, id_new, self, field, values[field],
|
||||
context=context)
|
||||
|
||||
if self._history_table:
|
||||
cursor.execute('INSERT INTO "' + self._history_table + '" ' \
|
||||
'(id' + upd0 + ') ' \
|
||||
'SELECT id' + upd0 + ' ' \
|
||||
'FROM "' + self._table + '" ' \
|
||||
'WHERE id = %s',(id_new,))
|
||||
|
||||
self._validate(cursor, user, [id_new], context=context)
|
||||
|
||||
# Check for Modified Preorder Tree Traversal
|
||||
@@ -290,14 +339,24 @@ class ModelSQL(ModelStorage):
|
||||
context=context)
|
||||
|
||||
fields_related = {}
|
||||
datetime_fields = []
|
||||
for field_name in fields_names:
|
||||
if field_name == '_timestamp':
|
||||
continue
|
||||
if '.' in field_name:
|
||||
field, field_related = field_name.split('.', 1)
|
||||
fields_related.setdefault(field, [])
|
||||
fields_related[field].append(field_related)
|
||||
elif field_name in self._columns:
|
||||
field = self._columns[field_name]
|
||||
else:
|
||||
field = self._inherit_fields[field_name][2]
|
||||
if hasattr(field, 'datetime_field') and field.datetime_field:
|
||||
datetime_fields.append(field.datetime_field)
|
||||
|
||||
# all inherited fields + all non inherited fields
|
||||
fields_pre = [x for x in fields_names + fields_related.keys() \
|
||||
fields_pre = [x for x in \
|
||||
fields_names + fields_related.keys() + datetime_fields \
|
||||
if (x in self._columns and \
|
||||
not hasattr(self._columns[x], 'set')) or \
|
||||
(x == '_timestamp')] + \
|
||||
@@ -306,9 +365,23 @@ class ModelSQL(ModelStorage):
|
||||
res = []
|
||||
table_query = ''
|
||||
table_args = []
|
||||
|
||||
if self.table_query(context):
|
||||
table_query, table_args = self.table_query(context)
|
||||
table_query = '(' + table_query + ') AS '
|
||||
|
||||
in_max = cursor.IN_MAX
|
||||
history_order = ''
|
||||
history_clause = ''
|
||||
history_limit = ''
|
||||
history_args = []
|
||||
if self._history_table and context.get('_datetime') and not table_query:
|
||||
in_max = 1
|
||||
table_query = self._history_table + ' AS '
|
||||
history_clause = ' AND (COALESCE(write_date, create_date) <= %s)'
|
||||
history_order = ' ORDER BY COALESCE(write_date, create_date) DESC'
|
||||
history_limit = ' LIMIT 1'
|
||||
history_args = [context['_datetime']]
|
||||
if len(fields_pre) :
|
||||
fields_pre2 = [(x in ('create_date', 'write_date')) \
|
||||
and ('date_trunc(\'second\', ' + x + ') as ' + x) \
|
||||
@@ -316,38 +389,23 @@ class ModelSQL(ModelStorage):
|
||||
if x != '_timestamp']
|
||||
if '_timestamp' in fields_pre:
|
||||
if not self.table_query(context):
|
||||
fields_pre2 += ['(CASE WHEN write_date IS NOT NULL ' \
|
||||
'THEN write_date ELSE create_date END) ' \
|
||||
fields_pre2 += ['(COALESCE(write_date, create_date)) ' \
|
||||
'AS _timestamp']
|
||||
else:
|
||||
fields_pre2 += ['now()::timestamp AS _timestamp']
|
||||
|
||||
if len(ids) > cursor.IN_MAX:
|
||||
cursor.execute('SELECT id ' \
|
||||
'FROM ' + table_query + '"' + self._table + '" ' \
|
||||
'ORDER BY ' + \
|
||||
','.join([self._table + '.' + x[0] + ' ' + x[1]
|
||||
for x in self._order]), table_args)
|
||||
i = 0
|
||||
ids_sorted = {}
|
||||
for row in cursor.fetchall():
|
||||
ids_sorted[row[0]] = i
|
||||
i += 1
|
||||
ids = ids[:]
|
||||
ids.sort(lambda x, y: ids_sorted[x] - ids_sorted[y])
|
||||
|
||||
for i in range(0, len(ids), cursor.IN_MAX):
|
||||
sub_ids = ids[i:i + cursor.IN_MAX]
|
||||
for i in range(0, len(ids), in_max):
|
||||
sub_ids = ids[i:i + in_max]
|
||||
if domain1:
|
||||
cursor.execute(('SELECT ' + \
|
||||
cursor.execute('SELECT ' + \
|
||||
','.join(fields_pre2 + ['id']) + \
|
||||
' FROM ' + table_query + '\"' + self._table +'\" ' \
|
||||
'WHERE id IN ' \
|
||||
'(' + ','.join(['%s' for x in sub_ids]) + ')'\
|
||||
' AND (' + domain1 + ') ORDER BY ' + \
|
||||
','.join([self._table + '.' + x[0] + ' ' + x[1] \
|
||||
for x in self._order])),
|
||||
table_args + sub_ids + domain2)
|
||||
'(' + ','.join(['%s' for x in sub_ids]) + ')' + \
|
||||
history_clause + \
|
||||
' AND (' + domain1 + ') ' + history_order + \
|
||||
history_limit,
|
||||
table_args + sub_ids + history_args + domain2)
|
||||
if not cursor.rowcount == len({}.fromkeys(sub_ids)):
|
||||
raise Exception('AccessError',
|
||||
'You try to bypass an access rule ' \
|
||||
@@ -358,10 +416,9 @@ class ModelSQL(ModelStorage):
|
||||
','.join(fields_pre2 + ['id']) + \
|
||||
' FROM ' + table_query + '\"' + self._table + '\" ' \
|
||||
'WHERE id IN ' \
|
||||
'(' + ','.join(['%s' for x in sub_ids]) + ')'\
|
||||
' ORDER BY ' + \
|
||||
','.join([self._table + '.' + x[0] + ' ' + x[1] \
|
||||
for x in self._order]), table_args + sub_ids)
|
||||
'(' + ','.join(['%s' for x in sub_ids]) + ')' + \
|
||||
history_clause + history_order + history_limit,
|
||||
table_args + sub_ids + history_args)
|
||||
res.extend(cursor.dictfetchall())
|
||||
else:
|
||||
res = [{'id': x} for x in ids]
|
||||
@@ -381,8 +438,8 @@ class ModelSQL(ModelStorage):
|
||||
field = self._inherits[table]
|
||||
inherits_fields = list(
|
||||
set(self._inherit_fields.keys()).intersection(
|
||||
set(fields_names + fields_related.keys())).difference(
|
||||
set(self._columns.keys())))
|
||||
set(fields_names + fields_related.keys() + datetime_fields)
|
||||
).difference(set(self._columns.keys())))
|
||||
if not inherits_fields:
|
||||
continue
|
||||
inherit_related_fields = []
|
||||
@@ -403,13 +460,15 @@ class ModelSQL(ModelStorage):
|
||||
|
||||
for record in res:
|
||||
record.update(res3[record[field]])
|
||||
if field not in fields_names + fields_related.keys():
|
||||
if field not in \
|
||||
fields_names + fields_related.keys() + datetime_fields:
|
||||
del record[field]
|
||||
|
||||
ids = [x['id'] for x in res]
|
||||
|
||||
# all non inherited fields for which there is a get attribute
|
||||
fields_post = [x for x in fields_names + fields_related.keys() \
|
||||
fields_post = [x for x in \
|
||||
fields_names + fields_related.keys() + datetime_fields \
|
||||
if x in self._columns \
|
||||
and hasattr(self._columns[x], 'get')]
|
||||
func_fields = {}
|
||||
@@ -436,19 +495,33 @@ class ModelSQL(ModelStorage):
|
||||
|
||||
to_del = []
|
||||
fields_related2values = {}
|
||||
for field in fields_related.keys():
|
||||
for field in fields_related.keys() + datetime_fields:
|
||||
if field not in fields_names:
|
||||
to_del.append(field)
|
||||
if field not in self._columns:
|
||||
continue
|
||||
if field not in fields_related.keys():
|
||||
continue
|
||||
fields_related2values.setdefault(field, {})
|
||||
if self._columns[field]._type == 'many2one':
|
||||
obj = self.pool.get(self._columns[field].model_name)
|
||||
for record in obj.read(cursor, user, [x[field] for x in res
|
||||
if x[field]], fields_related[field], context=context):
|
||||
record_id = record['id']
|
||||
del record['id']
|
||||
fields_related2values[field][record_id] = record
|
||||
if hasattr(self._columns[field], 'datetime_field') \
|
||||
and self._columns[field].datetime_field:
|
||||
ctx = context.copy()
|
||||
for record in res:
|
||||
ctx['_datetime'] = \
|
||||
record[self._columns[field].datetime_field]
|
||||
record2 = obj.read(cursor, user, record[field],
|
||||
fields_related[field], context=ctx)
|
||||
record_id = record2['id']
|
||||
del record2['id']
|
||||
fields_related2values[field][record_id] = record2
|
||||
else:
|
||||
for record in obj.read(cursor, user, [x[field] for x in res
|
||||
if x[field]], fields_related[field], context=context):
|
||||
record_id = record['id']
|
||||
del record['id']
|
||||
fields_related2values[field][record_id] = record
|
||||
elif self._columns[field]._type == 'reference':
|
||||
for record in res:
|
||||
if not record[field]:
|
||||
@@ -465,7 +538,7 @@ class ModelSQL(ModelStorage):
|
||||
del record2['id']
|
||||
fields_related2values[field][record_id] = record2
|
||||
|
||||
if to_del or fields_related.keys():
|
||||
if to_del or fields_related.keys() or datetime_fields:
|
||||
for record in res:
|
||||
for field in fields_related.keys():
|
||||
if field not in self._columns:
|
||||
@@ -570,8 +643,8 @@ class ModelSQL(ModelStorage):
|
||||
if not hasattr(self._columns[field], 'set'):
|
||||
if (not self._columns[field].translate) \
|
||||
or (context.get('language') or 'en_US') == 'en_US':
|
||||
upd0.append('"' + field + '"=' + \
|
||||
FIELDS[self._columns[field]._type].symbol_c)
|
||||
upd0.append(('"' + field + '"',
|
||||
FIELDS[self._columns[field]._type].symbol_c))
|
||||
upd1.append(FIELDS[self._columns[field]._type].symbol_f(
|
||||
values[field]))
|
||||
direct.append(field)
|
||||
@@ -602,51 +675,52 @@ class ModelSQL(ModelStorage):
|
||||
'is not in the selection' % \
|
||||
(val, field))
|
||||
|
||||
upd0.append('write_uid = %s')
|
||||
upd0.append('write_date = now()')
|
||||
upd0.append(('write_uid', '%s'))
|
||||
upd0.append(('write_date', 'now()'))
|
||||
upd1.append(user)
|
||||
|
||||
if len(upd0):
|
||||
domain1, domain2 = self.pool.get('ir.rule').domain_get(cursor,
|
||||
user, self._name, context=context)
|
||||
domain1, domain2 = self.pool.get('ir.rule').domain_get(cursor,
|
||||
user, self._name, context=context)
|
||||
if domain1:
|
||||
domain1 = ' AND (' + domain1 + ') '
|
||||
for i in range(0, len(ids), cursor.IN_MAX):
|
||||
sub_ids = ids[i:i + cursor.IN_MAX]
|
||||
ids_str = ','.join(['%s' for x in sub_ids])
|
||||
if domain1:
|
||||
domain1 = ' AND (' + domain1 + ') '
|
||||
for i in range(0, len(ids), cursor.IN_MAX):
|
||||
sub_ids = ids[i:i + cursor.IN_MAX]
|
||||
ids_str = ','.join(['%s' for x in sub_ids])
|
||||
if domain1:
|
||||
cursor.execute('SELECT id FROM "' + self._table + '" ' \
|
||||
'WHERE id IN (' + ids_str + ') ' + domain1,
|
||||
sub_ids + domain2)
|
||||
if not cursor.rowcount == len({}.fromkeys(sub_ids)):
|
||||
raise Exception('AccessError',
|
||||
'You try to bypass an access rule ' \
|
||||
'(Document type: %s).' % \
|
||||
self._description)
|
||||
else:
|
||||
cursor.execute('SELECT id FROM "' + self._table + '" ' \
|
||||
'WHERE id IN (' + ids_str + ')', sub_ids)
|
||||
if not cursor.rowcount == len({}.fromkeys(sub_ids)):
|
||||
raise Exception('AccessError',
|
||||
'You try to bypass an access rule ' \
|
||||
'(Document type: %s).' % \
|
||||
self._description)
|
||||
if domain1:
|
||||
cursor.execute('UPDATE "' + self._table + '" ' \
|
||||
'SET ' + ','.join(upd0) + ' ' \
|
||||
'WHERE id IN (' + ids_str + ') ' + domain1,
|
||||
upd1 + sub_ids + domain2)
|
||||
else:
|
||||
cursor.execute('UPDATE "' + self._table + '" ' \
|
||||
'SET ' + ','.join(upd0) + ' ' \
|
||||
'WHERE id IN (' + ids_str + ') ', upd1 + sub_ids)
|
||||
cursor.execute('SELECT id FROM "' + self._table + '" ' \
|
||||
'WHERE id IN (' + ids_str + ') ' + domain1,
|
||||
sub_ids + domain2)
|
||||
if not cursor.rowcount == len({}.fromkeys(sub_ids)):
|
||||
raise Exception('AccessError',
|
||||
'You try to bypass an access rule ' \
|
||||
'(Document type: %s).' % \
|
||||
self._description)
|
||||
else:
|
||||
cursor.execute('SELECT id FROM "' + self._table + '" ' \
|
||||
'WHERE id IN (' + ids_str + ')', sub_ids)
|
||||
if not cursor.rowcount == len({}.fromkeys(sub_ids)):
|
||||
raise Exception('AccessError',
|
||||
'You try to bypass an access rule ' \
|
||||
'(Document type: %s).' % \
|
||||
self._description)
|
||||
if domain1:
|
||||
cursor.execute('UPDATE "' + self._table + '" ' \
|
||||
'SET ' + \
|
||||
','.join([x[0] + ' = ' + x[1] for x in upd0]) + ' ' \
|
||||
'WHERE id IN (' + ids_str + ') ' + domain1,
|
||||
upd1 + sub_ids + domain2)
|
||||
else:
|
||||
cursor.execute('UPDATE "' + self._table + '" ' \
|
||||
'SET ' + \
|
||||
','.join([x[0] + ' = '+ x[1] for x in upd0]) + ' ' \
|
||||
'WHERE id IN (' + ids_str + ') ', upd1 + sub_ids)
|
||||
|
||||
for field in direct:
|
||||
if self._columns[field].translate:
|
||||
self.pool.get('ir.translation')._set_ids(cursor, user,
|
||||
self._name + ',' + field, 'model',
|
||||
context.get('language') or 'en_US', ids,
|
||||
values[field])
|
||||
for field in direct:
|
||||
if self._columns[field].translate:
|
||||
self.pool.get('ir.translation')._set_ids(cursor, user,
|
||||
self._name + ',' + field, 'model',
|
||||
context.get('language') or 'en_US', ids,
|
||||
values[field])
|
||||
|
||||
# call the 'set' method of fields which are not classic_write
|
||||
upd_todo.sort(lambda x, y: self._columns[x].priority - \
|
||||
@@ -656,6 +730,16 @@ class ModelSQL(ModelStorage):
|
||||
self._columns[field].set(cursor, user, select_id, self, field,
|
||||
values[field], context=context)
|
||||
|
||||
if self._history_table:
|
||||
columns = ['"' + str(x) + '"' for x in self._columns
|
||||
if not hasattr(self._columns[x], 'set')]
|
||||
for obj_id in ids:
|
||||
cursor.execute('INSERT INTO "' + self._history_table + '" ' \
|
||||
'(' + ','.join(columns) + ') ' \
|
||||
'SELECT ' + ','.join(columns) + ' ' + \
|
||||
'FROM "' + self._table + '" ' \
|
||||
'WHERE id = %s', (obj_id,))
|
||||
|
||||
for table in self._inherits:
|
||||
col = self._inherits[table]
|
||||
nids = []
|
||||
@@ -779,6 +863,12 @@ class ModelSQL(ModelStorage):
|
||||
cursor.execute('DELETE FROM "'+self._table+'" ' \
|
||||
'WHERE id IN (' + str_d + ')', sub_ids)
|
||||
|
||||
if self._history_table:
|
||||
for obj_id in ids:
|
||||
cursor.execute('INSERT INTO "' + self._history_table + '" ' \
|
||||
'(id, write_uid, write_date) VALUES (%s, %s, now())',
|
||||
(obj_id, user))
|
||||
|
||||
for k in tree_ids.keys():
|
||||
field = self._columns[k]
|
||||
if len(tree_ids[k]) == 1:
|
||||
@@ -793,6 +883,9 @@ class ModelSQL(ModelStorage):
|
||||
context=None, count=False, query_string=False):
|
||||
rule_obj = self.pool.get('ir.rule')
|
||||
|
||||
if context is None:
|
||||
context = {}
|
||||
|
||||
# Get domain clauses
|
||||
qu1, qu2, tables, tables_args = self.search_domain(cursor, user,
|
||||
domain, context=context)
|
||||
@@ -838,12 +931,31 @@ class ModelSQL(ModelStorage):
|
||||
res = cursor.fetchall()
|
||||
return res[0][0]
|
||||
# execute the "main" query to fetch the ids we were searching for
|
||||
query_str = 'SELECT %s.id FROM ' % self._table + \
|
||||
select_field = self._table + '.id'
|
||||
if self._history_table and context.get('_datetime') \
|
||||
and not query_string:
|
||||
select_field += ', COALESCE(' + self._table + '.write_date, ' + \
|
||||
self._table + '.create_date)'
|
||||
query_str = 'SELECT ' + select_field + ' FROM ' + \
|
||||
' '.join(tables) + ' WHERE ' + (qu1 or 'True') + \
|
||||
' ORDER BY ' + order_by + limit_str + offset_str
|
||||
if query_string:
|
||||
return (query_str, tables_args + qu2)
|
||||
cursor.execute(query_str, tables_args + qu2)
|
||||
|
||||
if self._history_table and context.get('_datetime'):
|
||||
res = []
|
||||
ids_date = {}
|
||||
for row in cursor.fetchall():
|
||||
if row[0] in ids_date:
|
||||
if row[1] <= ids_date[row[0]]:
|
||||
continue
|
||||
if row[0] in res:
|
||||
res.remove(row[0])
|
||||
res.append(row[0])
|
||||
ids_date[row[0]] = row[1]
|
||||
return res
|
||||
|
||||
res = cursor.fetchall()
|
||||
return [x[0] for x in res]
|
||||
|
||||
@@ -871,10 +983,19 @@ class ModelSQL(ModelStorage):
|
||||
table_query, tables_args = self.table_query(context)
|
||||
table_query = '(' + table_query + ') AS '
|
||||
|
||||
if self._history_table and context.get('_datetime'):
|
||||
table_query = self._history_table + ' AS '
|
||||
|
||||
tables = [table_query + '"' + self._table + '"']
|
||||
|
||||
qu1, qu2 = self.__search_domain_oper(cursor, user, domain, tables,
|
||||
tables_args, context=context)
|
||||
if self._history_table and context.get('_datetime'):
|
||||
if qu1:
|
||||
qu1 += ' AND'
|
||||
qu1 += ' (COALESCE(' + self._table + '.write_date, ' + \
|
||||
self._table + '.create_date) <= %s)'
|
||||
qu2 += [context['_datetime']]
|
||||
return qu1, qu2, tables, tables_args
|
||||
|
||||
def __search_domain_oper(self, cursor, user, domain, tables, tables_args,
|
||||
|
||||
@@ -103,7 +103,7 @@ class ModelStorage(Model):
|
||||
:param context: the context
|
||||
:return: a list of dictionnary or a dictionnary if ids is an id
|
||||
the dictionnaries will have fields names as key
|
||||
and fields value as value
|
||||
and fields value as value. The list will not be in the same order.
|
||||
'''
|
||||
model_access_obj = self.pool.get('ir.model.access')
|
||||
|
||||
|
||||
Reference in new issue
Block a user