Allow to use related fields (many2one and reference) in read

Use rec_name function field instead of name_get and name_search
Remove get function on many2one field
Don't put record name in reference field
Handle rec_name in default_get so default value for many2one are now only id
This commit is contained in:
Cédric Krier
2009-02-17 11:40:31 +01:00
parent 762a8545e7
commit 66f0ada474
15 changed files with 185 additions and 162 deletions
+2
View File
@@ -1,3 +1,5 @@
* 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
* Move workflow in ModelWorkflow and the workflow module
* Remove Service and LocalService objects
+1 -2
View File
@@ -257,8 +257,7 @@ class ActionReport(OSV):
('format', '=', 'odt'),
], limit=1, context=context)
if formats:
return format_obj.name_get(cursor, user, formats[0],
context=context)[0]
return formats[0]
return False
def default_module(self, cursor, user, context=None):
+1 -2
View File
@@ -72,8 +72,7 @@ class Cron(OSV):
return 5
def default_user(self, cursor, user, context=None):
user_obj = self.pool.get('res.user')
return user_obj.name_get(cursor, user, user, context=context)[0]
return user
def default_interval_number(self, cursor, user, context=None):
return 1
+3 -2
View File
@@ -148,8 +148,9 @@ class UIMenu(OSV):
], context=ctx)
if action_id:
action_id = action_id[0]
action_name = action_obj.name_get(cursor, user, action_id,
context=context)[0][1]
action = action_obj.browse(cursor, user, action_id,
context=context)
action_name = action.rec_name
else:
action_id = 0
action_name = ''
+2 -9
View File
@@ -118,18 +118,11 @@ class BrowseRecord(object):
continue
model = self._model.pool.get(j.model_name)
if j._type in ('many2one',):
if data[i]:
if isinstance(data[i][0], (list, tuple)):
ids2 = data[i][0][0]
else:
ids2 = data[i][0]
else:
ids2 = data[i]
if ids2 is False:
if not data[i]:
data[i] = BrowseRecordNull()
else:
data[i] = BrowseRecord(self._cursor, self._user,
ids2, model, self._cache,
data[i], model, self._cache,
context=self._context)
elif j._type in ('one2many', 'many2many') and len(data[i]):
data[i] = BrowseRecordList([BrowseRecord(self._cursor,
-26
View File
@@ -14,29 +14,3 @@ class Many2One(Field):
self.left = left
self.right = right
self.ondelete = ondelete
def get(self, cursor, user, ids, model, name, values=None, context=None):
if values is None:
values = {}
res = {}
for i in values:
res[i['id']] = i[name]
for i in ids:
res.setdefault(i, '')
try:
model = model.pool.get(self.model_name)
except KeyError:
return res
record_names = {}
for record_id, name in model.name_get(cursor, user,
[isinstance(x, (list, tuple)) and x[0] or x
for x in res.values() if x],
context=context):
record_names[record_id] = name
for i in res.keys():
if res[i] and res[i] in record_names:
res[i] = (res[i], record_names[res[i]])
else:
res[i] = False
return res
+1 -1
View File
@@ -25,7 +25,7 @@ class One2Many(Field):
[(self.field, 'in', sub_ids)], context=context)
for i in model.pool.get(self.model_name).read(cursor, user, ids2,
[self.field], context=context):
res[i[self.field][0]].append( i['id'] )
res[i[self.field]].append(i['id'])
return res
def set(self, cursor, user, record_id, model, name, values, context=None):
-12
View File
@@ -14,18 +14,6 @@ class Property(Function):
property_obj = model.pool.get('ir.property')
res = property_obj.get(cursor, user, name, model._name, ids,
context=context)
if self.model_name:
model = model.pool.get(self.model_name)
record_names = {}
for record_id, record_name in model.name_get(cursor, user,
[x for x in res.values() if x], context=context):
record_names[record_id] = record_name
for i in ids:
if res.get(i) and res[i] in record_names:
res[i] = (res[i], record_names[res[i]])
else:
res[i] = False
return res
+1 -10
View File
@@ -46,14 +46,5 @@ class Reference(Field):
('id', '=', ref_id),
], context=ctx):
ref_id = False
if ref_id:
ref_name = ref_obj.name_get(cursor, user, ref_id,
context=context)
if ref_name:
ref_name = ref_name[0][1]
else:
ref_name = ''
else:
ref_name = ''
res[i] = ref_model + ',(' + str(ref_id) + ',"' + ref_name + '")'
res[i] = ref_model + ',' + str(ref_id)
return res
+16 -18
View File
@@ -433,13 +433,13 @@ class Model(object):
property_obj = self.pool.get('ir.property')
value[field] = property_obj.get(cursor, user, field,
self._name)
if self._columns[field]._type in ('many2one',) \
and value[field]:
obj = self.pool.get(self._columns[field].model_name)
if isinstance(value[field], (int, long)) \
and hasattr(obj, 'name_get'):
value[field] = obj.name_get(cursor, user,
value[field], context=context)[0]
if self._columns[field]._type in ('many2one',) \
and value.get(field):
obj = self.pool.get(self._columns[field].model_name)
if 'rec_name' in obj._columns:
value[field + '.rec_name'] = obj.browse(cursor,
user, value[field],
context=context).rec_name
# get the default values set by the user and override the default
# values defined in the object
@@ -457,10 +457,10 @@ class Model(object):
('id', '=', field_value),
]):
continue
if isinstance(field_value, (int, long)) \
and hasattr(obj, 'name_get'):
field_value = obj.name_get(cursor, user, field_value,
context=context)[0]
if 'rec_name' in obj._columns:
value[field + '.rec_name'] = obj.browse(cursor,
user, field_value,
context=context).rec_name
if fld_def._type in ('many2many'):
obj = self.pool.get(fld_def.model_name)
field_value2 = []
@@ -487,13 +487,11 @@ class Model(object):
('id', '=', field_value[i][field2]),
]):
continue
if isinstance(field_value[i][field2],
(int, long)) \
and hasattr(obj2, 'name_get'):
field_value[i][field2] = obj2.name_get(
cursor, user,
field_value[i][field2],
context=context)[0]
if 'rec_name' in obj2._columns:
field_value[i][field2 + '.rec_name'] = \
obj2.browse(cursor, user,
field_value[i][field2],
context=context).rec_name
# TODO add test for many2many and one2many
field_value2[i][field2] = field_value[i][field2]
field_value = field_value2
+101 -22
View File
@@ -286,9 +286,17 @@ class ModelSQL(ModelStorage):
domain1, domain2 = rule_obj.domain_get(cursor, user, self._name,
context=context)
fields_related = {}
for field_name in fields_names:
if '.' in field_name:
field, field_related = field_name.split('.', 1)
fields_related.setdefault(field, [])
fields_related[field].append(field_related)
# all inherited fields + all non inherited fields
fields_pre = [x for x in fields_names if (x in self._columns \
and not hasattr(self._columns[x], 'set')) or \
fields_pre = [x for x in fields_names + fields_related.keys() \
if (x in self._columns and \
not hasattr(self._columns[x], 'set')) or \
(x == '_timestamp')] + \
self._inherits.values()
@@ -370,12 +378,19 @@ class ModelSQL(ModelStorage):
field = self._inherits[table]
inherits_fields = list(
set(self._inherit_fields.keys()).intersection(
set(fields_names)).difference(
set(fields_names + fields_related.keys())).difference(
set(self._columns.keys())))
if not inherits_fields:
continue
inherit_related_fields = []
for inherit_field in inherits_fields:
if inherit_field in fields_related:
for field_related in fields_related[inherit_field]:
inherit_related_fields.append(
inherit_field + '.' + field_related)
res2 = self.pool.get(table).read(cursor, user,
[x[field] for x in res], fields_names=inherits_fields,
[x[field] for x in res],
fields_names=inherits_fields + inherit_related_fields,
context=context)
res3 = {}
@@ -385,13 +400,14 @@ class ModelSQL(ModelStorage):
for record in res:
record.update(res3[record[field]])
if field not in fields_names:
if field not in fields_names + fields_related.keys():
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 if x in self._columns \
fields_post = [x for x in fields_names + fields_related.keys() \
if x in self._columns \
and hasattr(self._columns[x], 'get')]
func_fields = {}
for field in fields_post:
@@ -415,6 +431,65 @@ class ModelSQL(ModelStorage):
for record in res:
record[field] = res2[field][record['id']]
to_del = []
fields_related2values = {}
for field in fields_related.keys():
if field not in fields_names:
to_del.append(field)
if field not in self._columns:
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
elif self._columns[field]._type == 'reference':
for record in res:
if not record[field]:
continue
model_name, record_id = record[field].split(',', 1)
if not model_name:
continue
record_id = int(record_id)
if not record_id:
continue
obj = self.pool.get(model_name)
record2 = obj.read(cursor, user, record_id,
fields_related[field], context=context)
del record2['id']
fields_related2values[field][record_id] = record2
if to_del or fields_related.keys():
for record in res:
for field in fields_related.keys():
if field not in self._columns:
continue
for related in fields_related[field]:
if self._columns[field]._type == 'many2one':
if record[field]:
record[field + '.' + related] = \
fields_related2values[field][
record[field]][related]
else:
record[field + '.' + related] = False
elif self._columns[field]._type == 'reference':
if record[field]:
model_name, record_id = record[field].split(
',', 1)
if not model_name:
continue
record_id = int(record_id)
if not record_id:
continue
record[field + '.' + related] = \
fields_related2values[field][
record_id][related]
for field in to_del:
del record[field]
if int_id:
return res[0]
return res
@@ -902,8 +977,9 @@ class ModelSQL(ModelStorage):
if isinstance(domain[i][2], basestring):
# get the ids of the records of the "distant" resource
ids2 = [x[0] for x in field_obj.name_search(cursor, user,
domain[i][2], [], domain[i][1], context=context)]
ids2 = [x[0] for x in field_obj.search(cursor, user, [
('rec_name', domain[i][1], domain[i][2]),
], context=context)]
else:
ids2 = domain[i][2]
@@ -951,9 +1027,10 @@ class ModelSQL(ModelStorage):
# XXX must find a solution for long id list
if domain[i][1] in ('child_of', 'not child_of'):
if isinstance(domain[i][2], basestring):
ids2 = [x[0] for x in self.pool.get(
field.model_name).name_search(cursor, user, domain[i][2], [],
'like', context=context)]
field_obj = self.pool.get(field.model_name)
ids2 = [x[0] for x in field_obj.search(cursor, user, [
('rec_name', 'ilike', domain[i][2]),
], context=context)]
elif isinstance(domain[i][2], (int, long)):
ids2 = [domain[i][2]]
else:
@@ -994,9 +1071,10 @@ class ModelSQL(ModelStorage):
table, domain[i][0]))
else:
if isinstance(domain[i][2], basestring):
res_ids = [x[0] for x in self.pool.get(field.model_name
).name_search(cursor, user, domain[i][2], [],
domain[i][1], context=context)]
field_obj = self.pool.get(field.model_name)
res_ids = [x[0] for x in field_obj.search(cursor, user, [
('rec_name', domain[i][1], domain[i][2]),
], context=context)]
else:
res_ids = domain[i][2]
if res_ids == True or res_ids == False:
@@ -1023,9 +1101,10 @@ class ModelSQL(ModelStorage):
# XXX must find a solution for long id list
if domain[i][1] in ('child_of', 'not child_of'):
if isinstance(domain[i][2], basestring):
ids2 = [x[0] for x in self.pool.get(
field.model_name).name_search(cursor, user, domain[i][2],
[], 'like', context=context)]
field_obj = self.pool.get(field.model_name)
ids2 = [x[0] for x in field_obj.search(cursor, user, [
('rec_name', 'like', domain[i][2]),
], context=context)]
elif isinstance(domain[i][2], (int, long)):
ids2 = [domain[i][2]]
else:
@@ -1082,11 +1161,11 @@ class ModelSQL(ModelStorage):
ids2, table, domain[i][0]), table)
else:
if isinstance(domain[i][2], basestring):
res_ids = self.pool.get(field.model_name).name_search(cursor,
user, domain[i][2], [], domain[i][1],
context=context)
domain[i] = (domain[i][0], 'in', [x[0] for x in res_ids],
table)
field_obj = self.pool.get(field.model_name)
res_ids = field_obj.search(cursor, user, [
(field_obj._rec_name, domain[i][1], domain[i][2]),
], context=context)
domain[i] = (domain[i][0], 'in', res_ids, table)
else:
domain[i] += (table,)
i += 1
+37 -36
View File
@@ -38,6 +38,8 @@ class ModelStorage(Model):
create_date = fields.DateTime('Create Date', required=True, readonly=True)
write_uid = fields.Many2One('res.user', 'Write User', readonly=True)
write_date = fields.DateTime('Write Date', readonly=True)
rec_name = fields.Function('get_rec_name', type='char', string='Name',
fnct_search='search_rec_name')
def __init__(self):
super(ModelStorage, self).__init__()
@@ -50,8 +52,6 @@ class ModelStorage(Model):
'search',
'search_count',
'search_read',
'name_get',
'name_search',
'export_data',
'import_data',
]
@@ -343,6 +343,8 @@ class ModelStorage(Model):
ids = self.search(cursor, user, domain, offset=offset, limit=limit,
order=order, context=context)
if limit == 1:
if not ids:
return []
ids = ids[0]
return self.read(cursor, user, ids, fields_names=fields_names,
context=context)
@@ -379,46 +381,43 @@ class ModelStorage(Model):
return domain
return process(domain)
def name_get(self, cursor, user, ids, context=None):
def get_rec_name(self, cursor, user, ids, name, arg, context=None):
'''
Return a list of tuple for each ids.
The tuple contains the id and the name of the record.
Return a dictionary with id as key and rec_name as value.
It is used by the Function field rec_name
:param cursor: the database cursor
:param user: the user id
:param ids: a list of ids or an id
:param ids: a list of ids
:param name: the name of the Function field
:param arg: the argument of the Function field
:param context: the context
:return: a list of tuple for each ids
:return: a dictionary
'''
if not ids:
return []
if isinstance(ids, (int, long)):
ids = [ids]
return [(r['id'], unicode(r[self._rec_name])) for r in self.read(cursor,
user, ids, [self._rec_name], context=context)]
return {}
res = {}
for record in self.browse(cursor, user, ids, context=context):
res[record.id] = unicode(record[self._rec_name])
return res
def name_search(self, cursor, user, name='', args=None, operator='ilike',
context=None, limit=None):
def search_rec_name(self, cursor, user, name, args, context=None):
'''
Return a list of tuple like in name_get
where the name and the domain match.
Return a list of arguments for search on rec_name
:param cursor: the database cursor
:param user: the user id
:param name: the name searched
:param args: a domain like in search
:param operator: the operator to use to compare name with _rec_name
:param name: the name of the Function field
:param args: the list of arguments
:param context: the context
:param limit: a integer to limit the result
:return: a list of tuple for each ids like in name_get
:return: a list of arguments
'''
if args is None:
args = []
if name:
args = ['AND', args, (self._rec_name, operator, name)]
ids = self.search(cursor, user, args, limit=limit, context=context)
res = self.name_get(cursor, user, ids, context=context)
return res
args2 = []
i = 0
while i < len(args):
args2.append((self._rec_name, args[i][1], args[i][2]))
i += 1
return args2
def browse(self, cursor, user, ids, context=None):
'''
@@ -588,9 +587,10 @@ class ModelStorage(Model):
if line[i]:
relation = \
fields_def[field[len(prefix)]]['relation']
res2 = self.pool.get(relation).name_search(cursor,
user, line[i], [], operator='=')
res = (res2 and res2[0][0]) or False
relation_obj = self.pool.get(relation)
res = relation_obj.search(cursor, user, [
('rec_name', '=', line[i]),
], limit=1, context=context)
if not res:
warning += ('Relation not found: ' + line[i] + \
' on ' + relation + ' !\n')
@@ -603,17 +603,18 @@ class ModelStorage(Model):
relation = \
fields_def[field[len(prefix)]]['relation']
for word in line[i].split(','):
res2 = self.pool.get(relation).name_search(
cursor, user, word, [], operator='=')
res3 = (res2 and res2[0][0]) or False
if not res3:
relation_obj = self.pool.get(relation)
res2 = relation_obj.search(cursor, user, [
('rec_name', '=', word),
], limit=1, context=context)
if not res2:
warning += ('Relation not found: ' + \
line[i] + ' on '+relation + ' !\n')
logger.warning(
'Relation not found: ' + line[i] + \
' on '+relation + ' !\n')
else:
res.append(res3)
res.append(res2)
if len(res):
res = [('set', res)]
else:
+3 -6
View File
@@ -59,8 +59,7 @@ class Request(OSV):
'History', readonly=True)
def default_act_from(self, cursor, user, context=None):
user_obj = self.pool.get('res.user')
return user_obj.name_get(cursor, user, user, context=context)[0]
return user
def default_state(self, cursor, user, context=None):
return 'draft'
@@ -207,12 +206,10 @@ class RequestHistory(OSV):
return 'No Name'
def default_act_from(self, cursor, user, context=None):
user_obj = self.pool.get('res.user')
return user_obj.name_get(cursor, user, user, context=context)[0]
return user
def default_act_to(self, cursor, user, context=None):
user_obj = self.pool.get('res.user')
return user_obj.name_get(cursor, user, user, context=context)[0]
return user
def default_date_sent(self, cursor, user, context=None):
return datetime.datetime.now()
+13 -12
View File
@@ -157,18 +157,19 @@ class User(OSV):
val['password'] = 'x' * 10
return res
def name_search(self, cursor, user, name='', args=None, operator='ilike',
context=None, limit=80):
if args is None:
args = []
ids = []
if name:
ids = self.search(cursor, user, [('login', '=', name)] + args,
limit=limit, context=context)
if not ids:
ids = self.search(cursor, user, [('name', operator, name)] + args,
limit=limit, context=context)
return self.name_get(cursor, user, ids, context=context)
def search_rec_name(self, cursor, user, name, args, context=None):
args2 = []
i = 0
while i < len(args):
ids = self.search(cursor, user, [
('login', '=', args[i][2]),
], context=context)
if len(ids) == 1:
args2.append(('id', '=', ids[0]))
else:
args2.append((self._rec_name, args[i][1], args[i][2]))
i += 1
return args2
def copy(self, cursor, user, ids, default=None, context=None):
if default is None:
+4 -4
View File
@@ -250,14 +250,14 @@ class Collection(OSV):
return res
model_ids = model_obj.search(cursor, user,
eval(collection.domain or "[]"), context=context)
for child_id, child_name in model_obj.name_get(cursor, user,
for child in model_obj.browse(cursor, user,
model_ids, context=context):
if '/' in child_name:
if '/' in child.rec_name:
continue
res.append(child_name + '-' + str(child_id))
res.append(child.rec_name + '-' + str(child.id))
if cache is not None:
cache.setdefault(model_obj._name, {})
cache[model_obj._name][child_id] = {}
cache[model_obj._name][child.id] = {}
return res
else:
for child in collection.childs: