@athelia Here is a custom field (initially written by @ced for us) 
class One2ManyDomain(One2Many):
'''
Behaves exaclty like a O2M field, but the domain on the field is also used
when reading it.
The 'bypass_active_test' attribute can be used to disable active checks
when reading the field.
'''
def __init__(self, *args, bypass_active_test=False, **kwargs):
super().__init__(*args, **kwargs)
self.bypass_active_test = bypass_active_test
@classmethod
def init_from_One2Many(cls, source):
return cls(source.model_name, source.field, source.string,
source.add_remove, source.order, source.datetime_field,
source.size, source.help, source.required, source.readonly,
source.domain, source.states, source.on_change,
source.on_change_with, source.depends, source.context,
source.loading, delete_missing=source._delete_missing,
target_not_required=source._target_not_required,
target_not_indexed=source._target_not_indexed)
def get(self, ids, model, name, values=None):
'''
Return target records ordered.
'''
pool = Pool()
Relation = pool.get(self.model_name)
if self.field in Relation._fields:
field = Relation._fields[self.field]
else:
field = Relation._inherit_fields[self.field][2]
res = {}
for i in ids:
res[i] = set(), []
targets = []
in_max = Transaction().database.IN_MAX
for i in range(0, len(ids), in_max):
sub_ids = ids[i:i + in_max]
if field._type == 'reference':
references = ['%s,%s' % (model.__name__, x) for x in sub_ids]
clause = [(self.field, 'in', references)]
else:
clause = [(self.field, 'in', sub_ids)]
def clean_domain(the_domain):
if not the_domain:
return []
if the_domain[0] in ('OR', 'AND'):
final_domain = [the_domain[0]]
for elem in the_domain[1:]:
good_domain = clean_domain(elem)
if not good_domain:
final_domain.append(())
else:
final_domain.append(good_domain)
elif isinstance(the_domain[0], (tuple, list)):
final_domain = []
for elem in the_domain:
good_domain = clean_domain(elem)
if not good_domain:
final_domain.append(())
else:
final_domain.append(good_domain)
else:
has_pyson = False
for value in the_domain:
if isinstance(value, PYSON):
has_pyson = True
break
if not has_pyson:
final_domain = the_domain
else:
final_domain = None
return final_domain
clause.append(clean_domain(self.domain))
with Transaction().set_context(
active_test=not self.bypass_active_test):
targets.append(Relation.search(clause, order=self.order))
targets = list(chain(*targets))
for target in targets:
origin_id = getattr(target, self.field).id
if target.id not in res[origin_id][0]:
# Use set / list combination to manage order
res[origin_id][0].add(target.id)
res[origin_id][1].append(target.id)
return dict((key, tuple(value[1])) for key, value in res.items())
We use this to solve the exact problem you have here.
Slight disclaimer : there are some caveats when using it, mostly you should not have “overlapping” One2Many / One2Many domain fields, else when they are set averything might go awry 