[FIX] base, web: don't fold M2M when not in import compatible mode

Before this commit, if the first exported field of an M2M is `id` (the
xid) the entire M2M is folded into a single cell with comma-separated
xids and any following field is ignored. If `id` is any but the first
field, the export behaves normally (with the m2m exported as a "table"
inside the parent record).

This behaviour makes sense for import-compatible exports where the id
is the only thing which can be exported anyway, but it is troublesome
outside of that mode as the behaviour of m2m under export becomes
incoherent/unpredictable (ish) as it depends on the position of the
m2m's `id` in the exports list.

Change it so we only perform folding in import-compatible mode (which
is the default for backwards compatibility with e.g. API calling
export_data directly & the like).

opw-813361

Fixes #22600
This commit is contained in:
Xavier Morel
2018-02-19 10:43:15 +01:00
committed by Nicolas Martinelli
parent 906a9af8f2
commit a583a56324
3 changed files with 53 additions and 4 deletions
+1 -1
View File
@@ -1335,7 +1335,7 @@ class ExportFormat(object):
model, fields, ids, domain, import_compat = \
operator.itemgetter('model', 'fields', 'ids', 'domain', 'import_compat')(params)
Model = request.env[model].with_context(**params.get('context', {}))
Model = request.env[model].with_context(import_compat=import_compat, **params.get('context', {}))
records = Model.browse(ids) or Model.search(domain, offset=0, limit=False, order=False)
if not Model._is_an_ordinary_table():
+48 -1
View File
@@ -600,7 +600,54 @@ class test_m2m(CreatorCase):
['', u'export.many2many.other:13'],
])
# essentially same as o2m, so boring
def test_multiple_records_subfield(self):
r = self.make(self.commands)
xid = self.env['ir.model.data'].create({
'name': 'whopwhopwhop',
'module': '__t__',
'model': r._name,
'res_id': r.id,
}).complete_name
sids = [
self.env['ir.model.data'].create({
'name': sub.str,
'module': '__t__',
'model': sub._name,
'res_id': sub.id,
}).complete_name
for sub in r.value
]
r.invalidate_cache()
self.assertEqual(
r._export_rows([['value', 'id']]),
[['__t__.record000,__t__.record001,__t__.record010,__t__.record011,__t__.record100']]
)
self.assertEqual(
r.with_context(import_compat=True)._export_rows([['value', 'id']]),
[['__t__.record000,__t__.record001,__t__.record010,__t__.record011,__t__.record100']]
)
self.assertEqual(
r.with_context(import_compat=False)._export_rows([['id'], ['value', 'id'], ['value', 'value']]),
[
[xid, u'__t__.record000', u'4'],
[u'', u'__t__.record001', u'42'],
[u'', u'__t__.record010', u'36'],
[u'', u'__t__.record011', u'4'],
[u'', u'__t__.record100', u'13']
]
)
self.assertEqual(
r.with_context(import_compat=False)._export_rows([['id'], ['value', 'value'], ['value', 'id']]),
[
[xid, u'4', u'__t__.record000'],
[u'', u'42', u'__t__.record001'],
[u'', u'36', u'__t__.record010'],
[u'', u'4', u'__t__.record011'],
[u'', u'13', u'__t__.record100']
]
)
class test_function(CreatorCase):
+4 -2
View File
@@ -758,6 +758,7 @@ class BaseModel(object):
:param fields: list of lists of fields to traverse
:return: list of lists of corresponding values
"""
import_compatible = self.env.context.get('import_compat', True)
lines = []
for record in self:
# main line of record, initially empty
@@ -791,8 +792,9 @@ class BaseModel(object):
else:
primary_done.append(name)
# This is a special case, its strange behavior is intended!
if field.type == 'many2many' and len(path) > 1 and path[1] == 'id':
# in import_compat mode, m2m should always be exported as
# a comma-separated list of xids in a single cell
if import_compatible and field.type == 'many2many' and len(path) > 1 and path[1] == 'id':
xml_ids = [r.__export_xml_id() for r in value]
current[i] = ','.join(xml_ids) or False
continue