diff --git a/tests/form_pages/test_computed_field.py b/tests/form_pages/test_computed_field.py index 6cefa3cb8..9300272f8 100644 --- a/tests/form_pages/test_computed_field.py +++ b/tests/form_pages/test_computed_field.py @@ -1,4 +1,5 @@ import datetime +import decimal import pytest from django.utils.timezone import make_aware @@ -330,6 +331,36 @@ def test_computed_field_complex_data(pub, http_requests): assert formdata.data['1'] == {'foo': 'bar'} +def test_computed_field_decimal_data(pub, http_requests): + FormDef.wipe() + + formdef = FormDef() + formdef.name = 'test' + formdef.fields = [ + fields.ComputedField( + id='1', + label='computed', + varname='computed', + value_template='{{ "123.45"|decimal }}', + freeze_on_initial_value=True, + ), + fields.CommentField(id='2', label='X{{form_var_computed}}Y', type='comment'), + ] + formdef.store() + formdef.data_class().wipe() + + resp = get_app(pub).get('/test/') + assert 'X123.45Y' in resp.text + resp = resp.forms[0].submit('submit') # -> validation + resp = resp.forms[0].submit('submit').follow() # -> submit + assert 'The form has been recorded' in resp.text + assert formdef.data_class().count() == 1 + formdata = formdef.data_class().select()[0] + # pickle storage keeps the typed data but postgresql storage has to convert + # it to stringfor json storage, hence the casting here: + assert decimal.Decimal(formdata.data['1']) == decimal.Decimal('123.45') + + def test_computed_field_usage_in_live_data(pub, http_requests): FormDef.wipe() diff --git a/wcs/sql.py b/wcs/sql.py index 529e3d15d..e3fee9037 100644 --- a/wcs/sql.py +++ b/wcs/sql.py @@ -17,6 +17,7 @@ import copy import datetime import io +import json import re import time import unicodedata @@ -47,7 +48,7 @@ from wcs.qommon import PICKLE_KWARGS, force_str from . import qommon from .publisher import UnpicklerClass from .qommon import _, get_cfg -from .qommon.misc import strftime +from .qommon.misc import JSONEncoder, strftime from .qommon.storage import _take, deep_bytes2str from .qommon.storage import parse_clause as parse_storage_clause from .qommon.substitution import invalidate_substitution_cache @@ -1700,7 +1701,7 @@ class SqlMixin: if value is not None: # embed value in a dict, so it's never necessary to cast the # value for postgresql - value = {'data': value, '@type': 'computed-data'} + value = {'data': json.loads(JSONEncoder().encode(value)), '@type': 'computed-data'} elif sql_type == 'varchar': assert isinstance(value, str) elif sql_type == 'date':