misc: use existing computed data fields when evaluating further fields (#55440)

This commit is contained in:
Frédéric Péters 2021-07-06 23:40:38 +02:00
parent 7f7781dbdb
commit 739a53eb5a
2 changed files with 71 additions and 9 deletions

View File

@ -477,3 +477,49 @@ def test_computed_field_edit_action(pub):
resp = resp.forms[0].submit('submit')
formdata.refresh_from_storage()
assert formdata.data == {'0': 'bar', '1': 'PLOP'}
def test_cascading_computed_fields(pub):
FormDef.wipe()
formdef = FormDef()
formdef.name = 'test'
formdef.fields = [
fields.PageField(
id='0',
label='1st page',
type='page',
post_conditions=[
{
'condition': {
'type': 'django',
'value': 'form_var_dc == "0abc"',
},
'error_message': 'You shall not pass.',
}
],
),
fields.ComputedField(id='1', label='computed', varname='a', value_template='a'),
fields.ComputedField(id='2', label='computed', varname='b', value_template='{{form_var_a}}b'),
fields.ComputedField(id='3', label='computed', varname='c', value_template='{{form_var_b}}c'),
fields.CommentField(id='4', label='X{{ form_var_c }}Y', type='comment'),
fields.StringField(id='5', label='string', varname='d'),
fields.ComputedField(id='6', label='computed', varname='da', value_template='{{form_var_d}}a'),
fields.ComputedField(id='7', label='computed', varname='db', value_template='{{form_var_da}}b'),
fields.ComputedField(id='8', label='computed', varname='dc', value_template='{{form_var_db}}c'),
]
formdef.store()
formdef.data_class().wipe()
resp = get_app(pub).get('/test/')
assert 'XabcY' in resp.text # check comment field has the correct value
# this should produce form_var_dc == "Xabc", and not pass the post condition
resp.forms[0]['f5'].value = 'X'
resp = resp.forms[0].submit('submit') # -> validation
assert 'You shall not pass.' in resp.text
# this should produce form_var_dc == "0abc", and be ok for the post condition
resp = get_app(pub).get('/test/')
resp.forms[0]['f5'].value = '0'
resp = resp.forms[0].submit('submit') # -> validation
assert 'You shall not pass.' not in resp.text

View File

@ -641,17 +641,33 @@ class FormPage(Directory, FormTemplateMixin):
return computed_values
if not computed_values:
get_session().add_magictoken('%s-computed' % magictoken, computed_values)
# create a temporary map using form variable names, to be used as context
# variables during evaluation (via temporary_feed below), so we can have
# computed fields depending on previously computed fields from the same page.
mapped_computed_values = {}
for field in fields:
if field.freeze_on_initial_value and field.id in computed_values:
continue
with get_publisher().complex_data():
try:
value = WorkflowStatusItem.compute(field.value_template, raises=True, allow_complex=True)
except TemplateError:
if field.id in computed_values:
mapped_computed_values['form_var_%s' % field.varname] = computed_values[field.id]
with get_publisher().substitutions.temporary_feed(mapped_computed_values, force_mode='lazy'):
for field in fields:
if field.freeze_on_initial_value and field.id in computed_values:
continue
else:
value = get_publisher().get_cached_complex_data(value)
computed_values[field.id] = value
with get_publisher().complex_data():
try:
value = WorkflowStatusItem.compute(
field.value_template, raises=True, allow_complex=True
)
except TemplateError:
continue
else:
value = get_publisher().get_cached_complex_data(value)
computed_values[field.id] = value
mapped_computed_values['form_var_%s' % field.varname] = value
get_publisher().substitutions.invalidate_cache()
return computed_values
def modify_filling_context(self, context, page, data):