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)