changeset c47b3642f1a6 in trytond:default
details: https://hg.tryton.org/trytond?cmd=changeset;node=c47b3642f1a6
description:
        Call getter function when accessing Function field

        If the record is unsaved and the getter is based on on_change_with, we 
can call
        the getter to compute the value.
        This value must not be stored in the cache as it may change prior to 
saving.

        issue4193
        issue9263
        review317291002
diffstat:

 CHANGELOG                            |   1 +
 trytond/model/fields/function.py     |  13 +++++++++++++
 trytond/tests/__init__.py            |   2 ++
 trytond/tests/field_function.py      |  32 ++++++++++++++++++++++++++++++++
 trytond/tests/test_field_function.py |  32 ++++++++++++++++++++++++++++++++
 5 files changed, 80 insertions(+), 0 deletions(-)

diffs (122 lines):

diff -r 3031a05ab010 -r c47b3642f1a6 CHANGELOG
--- a/CHANGELOG Sat May 02 10:29:26 2020 +0200
+++ b/CHANGELOG Sun May 03 14:34:44 2020 +0200
@@ -1,3 +1,4 @@
+* Call getter function when accessing Function field on unsaved record
 * Add language configuration wizard
 * Allow copying attachments and notes to created records
 * Add link button on form
diff -r 3031a05ab010 -r c47b3642f1a6 trytond/model/fields/function.py
--- a/trytond/model/fields/function.py  Sat May 02 10:29:26 2020 +0200
+++ b/trytond/model/fields/function.py  Sun May 03 14:34:44 2020 +0200
@@ -125,6 +125,19 @@
                         'ir.msg_setter_function_missing',
                         **Model.__names__(self.name)))
 
+    def __get__(self, inst, cls):
+        try:
+            return super().__get__(inst, cls)
+        except AttributeError:
+            if not self.getter.startswith('on_change_with'):
+                raise
+            value = getattr(inst, self.getter)(self.name)
+            # Use temporary instance to not modify instance values
+            temp_inst = cls()
+            # Set the value to have proper type
+            self.__set__(temp_inst, value)
+            return super().__get__(temp_inst, cls)
+
     def __set__(self, inst, value):
         self._field.__set__(inst, value)
 
diff -r 3031a05ab010 -r c47b3642f1a6 trytond/tests/__init__.py
--- a/trytond/tests/__init__.py Sat May 02 10:29:26 2020 +0200
+++ b/trytond/tests/__init__.py Sun May 03 14:34:44 2020 +0200
@@ -19,6 +19,7 @@
     from . import field_datetime
     from . import field_dict
     from . import field_float
+    from . import field_function
     from . import field_integer
     from . import field_many2many
     from . import field_many2one
@@ -58,6 +59,7 @@
     field_datetime.register('tests')
     field_dict.register('tests')
     field_float.register('tests')
+    field_function.register('tests')
     field_integer.register('tests')
     field_many2many.register('tests')
     field_many2one.register('tests')
diff -r 3031a05ab010 -r c47b3642f1a6 trytond/tests/field_function.py
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/trytond/tests/field_function.py   Sun May 03 14:34:44 2020 +0200
@@ -0,0 +1,32 @@
+# This file is part of Tryton.  The COPYRIGHT file at the top level of
+# this repository contains the full copyright notices and license terms.
+
+from trytond.model import ModelSQL, fields
+from trytond.pool import Pool
+
+
+class FunctionAccessor(ModelSQL):
+    "Function Accessor"
+    __name__ = 'test.function.accessor'
+
+    target = fields.Many2One('test.function.accessor.target', "Target")
+    function = fields.Function(
+        fields.Many2One('test.function.accessor.target', "Function"),
+        'on_change_with_function')
+
+    @fields.depends('target')
+    def on_change_with_function(self, name=None):
+        if self.target:
+            return self.target.id
+
+
+class FunctionAccessorTarget(ModelSQL):
+    "Function Accessor Target"
+    __name__ = 'test.function.accessor.target'
+
+
+def register(module):
+    Pool.register(
+        FunctionAccessor,
+        FunctionAccessorTarget,
+        module=module, type_='model')
diff -r 3031a05ab010 -r c47b3642f1a6 trytond/tests/test_field_function.py
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/trytond/tests/test_field_function.py      Sun May 03 14:34:44 2020 +0200
@@ -0,0 +1,32 @@
+# This file is part of Tryton.  The COPYRIGHT file at the top level of
+# this repository contains the full copyright notices and license terms.
+import unittest
+
+from trytond.pool import Pool
+from trytond.tests.test_tryton import activate_module, with_transaction
+
+
+class FieldFunctionTestCase(unittest.TestCase):
+    "Test Field Function"
+
+    @classmethod
+    def setUpClass(cls):
+        activate_module('tests')
+
+    @with_transaction()
+    def test_accessor(self):
+        "Test accessing field on unsaved instance"
+        pool = Pool()
+        Model = pool.get('test.function.accessor')
+        Target = pool.get('test.function.accessor.target')
+
+        target = Target()
+        target.save()
+        record = Model()
+        record.target = target
+
+        self.assertEqual(record.function, target)
+
+
+def suite():
+    return unittest.TestLoader().loadTestsFromTestCase(FieldFunctionTestCase)

Reply via email to