[FIX] OPW 598942 : orm read_group doesn't take referenced fields or aggregated fields in account when sorting
Sorting was done using a search on ids that where found in a custom SQL field, only 1 record among aggregated records with same groupby value was used when using search for ordering, resulting data ordered on max(aggregated_data).field_value instead of sum(aggregated_data.field_value). lp bug: https://launchpad.net/bugs/1060086 fixed bzr revid: acl@openerp.com-20140217172926-ka2fw8t2l3cqi7h3
This commit is contained in:
commit
90dcc00443
|
@ -289,15 +289,25 @@ class test_base(common.TransactionCase):
|
|||
{'name': 'Alice', 'login': 'alice', 'color': 1, 'function': 'Friend'},
|
||||
{'name': 'Bob', 'login': 'bob', 'color': 2, 'function': 'Friend'},
|
||||
{'name': 'Eve', 'login': 'eve', 'color': 3, 'function': 'Eavesdropper'},
|
||||
{'name': 'Nab', 'login': 'nab', 'color': 2, 'function': '5$ Wrench'},
|
||||
]:
|
||||
self.res_users.create(cr, uid, user_data)
|
||||
|
||||
#groupby='name',order='name DESC, color ASC'
|
||||
|
||||
groups_data = self.res_users.read_group(cr, uid, domain=[('login', 'in', ('alice', 'bob', 'eve'))], fields=['name', 'color', 'function'], groupby='function')
|
||||
self.assertEqual(len(groups_data), 2, "Incorrect number of results when grouping on a field")
|
||||
for group_data in groups_data:
|
||||
self.assertIn('color', group_data, "Aggregated data for the column 'color' is not present in read_group return values")
|
||||
self.assertEqual(group_data['color'], 3, "Incorrect sum for aggregated data for the column 'color'")
|
||||
|
||||
groups_data = self.res_users.read_group(cr, uid, domain=[('login', 'in', ('alice', 'bob', 'eve'))], fields=['name', 'color'], groupby='name', orderby='name DESC, color asc')
|
||||
self.assertEqual(len(groups_data), 3, "Incorrect number of results when grouping on a field")
|
||||
self.assertEqual([user['name'] for user in groups_data], ['Eve', 'Bob', 'Alice'], 'Incorrect ordering of the list')
|
||||
|
||||
groups_data = self.res_users.read_group(cr, uid, domain=[('login', 'in', ('alice', 'bob', 'eve', 'nab'))], fields=['function', 'color'], groupby='function', orderby='color ASC')
|
||||
self.assertEqual(len(groups_data), 3, "Incorrect number of results when grouping on a field")
|
||||
self.assertEqual(groups_data, sorted(groups_data, key=lambda x: x['color']), 'Incorrect ordering of the list')
|
||||
|
||||
class test_partner_recursion(common.TransactionCase):
|
||||
|
||||
def setUp(self):
|
||||
|
|
|
@ -2595,6 +2595,32 @@ class BaseModel(object):
|
|||
r['__fold'] = folded.get(r[groupby] and r[groupby][0], False)
|
||||
return result
|
||||
|
||||
def _read_group_generate_order_by(self, orderby, aggregated_fields, groupby, query):
|
||||
"""
|
||||
Generates the ORDER BY sql clause for the read group method. Adds the missing JOIN clause
|
||||
to the query if order should be computed against m2o field.
|
||||
:param orderby: the orderby definition in the form "%(field)s %(order)s"
|
||||
:param aggregated_fields: list of aggregated fields in the query
|
||||
:param groupby: the current groupby field name
|
||||
:param query: the query object used to construct the query afterwards
|
||||
"""
|
||||
orderby_list = []
|
||||
ob = ''
|
||||
for order_splits in orderby.split(','):
|
||||
order_split = order_splits.split()
|
||||
orderby_field = order_split[0]
|
||||
orderby_dir = len(order_split) == 2 and order_split[1].upper() == 'ASC' and 'ASC' or 'DESC'
|
||||
if orderby_field == groupby:
|
||||
ob = self._generate_order_by(order_splits, query).replace('ORDER BY ', '')
|
||||
orderby_list.append(ob)
|
||||
elif orderby_field in aggregated_fields:
|
||||
orderby_list.append('%s %s' % (orderby_field,orderby_dir))
|
||||
|
||||
if orderby_list:
|
||||
return ' ORDER BY %s' % (','.join(orderby_list)), ob and ob.split()[0] or ''
|
||||
else:
|
||||
return '', ''
|
||||
|
||||
def read_group(self, cr, uid, domain, fields, groupby, offset=0, limit=None, context=None, orderby=False):
|
||||
"""
|
||||
Get the list of records in list view grouped by the given ``groupby`` fields
|
||||
|
@ -2674,6 +2700,12 @@ class BaseModel(object):
|
|||
qualified_field = self._inherits_join_calc(f, query)
|
||||
flist += "%s(%s) AS %s" % (group_operator, qualified_field, f)
|
||||
|
||||
order = orderby or groupby
|
||||
orderby_clause = ''
|
||||
ob = ''
|
||||
if order:
|
||||
orderby_clause, ob = self._read_group_generate_order_by(order, aggregated_fields, groupby, query)
|
||||
|
||||
gb = groupby and (' GROUP BY ' + qualified_groupby_field) or ''
|
||||
|
||||
from_clause, where_clause, where_clause_params = query.get_sql()
|
||||
|
@ -2682,28 +2714,27 @@ class BaseModel(object):
|
|||
offset_str = offset and ' offset %d' % offset or ''
|
||||
if len(groupby_list) < 2 and context.get('group_by_no_leaf'):
|
||||
group_count = '_'
|
||||
cr.execute('SELECT min(%s.id) AS id, count(%s.id) AS %s_count' % (self._table, self._table, group_count) + (flist and ',') + flist + ' FROM ' + from_clause + where_clause + gb + limit_str + offset_str, where_clause_params)
|
||||
cr.execute('SELECT min(%s.id) AS id, count(%s.id) AS %s_count' % (self._table, self._table, group_count) + (flist and ',') + flist + ' FROM ' + from_clause + where_clause + gb + (ob and ',') + ob + orderby_clause + limit_str + offset_str, where_clause_params)
|
||||
alldata = {}
|
||||
groupby = group_by
|
||||
for r in cr.dictfetchall():
|
||||
|
||||
fetched_data = cr.dictfetchall()
|
||||
|
||||
data_ids = []
|
||||
for r in fetched_data:
|
||||
for fld, val in r.items():
|
||||
if val is None: r[fld] = False
|
||||
alldata[r['id']] = r
|
||||
data_ids.append(r['id'])
|
||||
del r['id']
|
||||
|
||||
order = orderby or groupby
|
||||
data_ids = self.search(cr, uid, [('id', 'in', alldata.keys())], order=order, context=context)
|
||||
|
||||
# the IDs of records that have groupby field value = False or '' should be included too
|
||||
data_ids += set(alldata.keys()).difference(data_ids)
|
||||
|
||||
if groupby:
|
||||
if groupby:
|
||||
data = self.read(cr, uid, data_ids, [groupby], context=context)
|
||||
# restore order of the search as read() uses the default _order (this is only for groups, so the footprint of data should be small):
|
||||
data_dict = dict((d['id'], d[groupby] ) for d in data)
|
||||
result = [{'id': i, groupby: data_dict[i]} for i in data_ids]
|
||||
else:
|
||||
result = [{'id': i} for i in data_ids]
|
||||
result = [{'id': i} for i in data_ids]
|
||||
|
||||
for d in result:
|
||||
if groupby:
|
||||
|
|
Loading…
Reference in New Issue