From fa9749fe4877770222369bc5f8cea31be26a15c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Tue, 24 Feb 2026 11:34:42 +0100 Subject: [PATCH] Support fmany2one based on Function fields --- trytond/CHANGELOG | 1 + trytond/trytond/model/fields/fmany2one.py | 25 ++++++++++++++++++----- 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/trytond/CHANGELOG b/trytond/CHANGELOG index 796cb83d31..0a50e05933 100644 --- a/trytond/CHANGELOG +++ b/trytond/CHANGELOG @@ -1,3 +1,4 @@ +* Support fmany2one based on Function fields * Add timestamp field on ModelSQL for last modified * Support Function field without getter but SQL expression * Add support for column_ method diff --git a/trytond/trytond/model/fields/fmany2one.py b/trytond/trytond/model/fields/fmany2one.py index 43caa6a688..de3f8fd3d3 100644 --- a/trytond/trytond/model/fields/fmany2one.py +++ b/trytond/trytond/model/fields/fmany2one.py @@ -31,10 +31,22 @@ def fmany2one( pool = Pool() Target = pool.get(target_model) table_h = cls.__table_handler__(module) + target_h = Target.__table_handler__(module) super().__register__(module) - table_h.add_fk( - sources, Target._table, target_fields, - on_delete=getattr(cls, name).ondelete) + if (all(table_h.column_exist(s) for s in sources) + and all(target_h.column_exist(t) for t in target_fields)): + table_h.add_fk( + sources, Target._table, target_fields, + on_delete=getattr(cls, name).ondelete) + + @classmethod + def __setup__(cls): + super().__setup__() + if any(isinstance(getattr(cls, s), Function) for s in sources): + try: + delattr(Mixin, f'domain_{name}') + except AttributeError: + pass @classmethod def preprocess_values(cls, mode, values): @@ -92,8 +104,11 @@ def fmany2one( setattr(Mixin, name, Function( Many2One(target_model, string, ondelete=ondelete, **kwargs), - f'get_{name}', setter=f'set_{name}')) + f'get_{name}', + setter=f'set_{name}' + if not kwargs.get('readonly', False) else None)) setattr(Mixin, f'get_{name}', getter) - setattr(Mixin, f'set_{name}', setter) + if not kwargs.get('readonly', False): + setattr(Mixin, f'set_{name}', setter) setattr(Mixin, f'domain_{name}', searcher) return Mixin