general: add support for filtering on computed data fields (#55891)

This commit is contained in:
Frédéric Péters 2021-08-03 08:59:01 +02:00
parent e9c5baba07
commit 21f7ccf668
4 changed files with 60 additions and 4 deletions

View File

@ -523,3 +523,54 @@ def test_cascading_computed_fields(pub):
resp.forms[0]['f5'].value = '0'
resp = resp.forms[0].submit('submit') # -> validation
assert 'You shall not pass.' not in resp.text
def test_computed_field_usage_in_criteria(pub):
FormDef.wipe()
formdef = FormDef()
formdef.name = 'test'
formdef.fields = [
fields.PageField(
id='0',
label='1st page',
type='page',
),
fields.ComputedField(
id='1',
label='computed',
varname='computed',
value_template='{{ request.GET.param }}',
freeze_on_initial_value=True,
),
fields.PageField(
id='2',
label='2nd page',
type='page',
),
fields.CommentField(
id='3',
label='<p>count with this value: '
'{{form_objects|exclude_self|filter_by:"computed"|filter_value:form_var_computed|count}}</p>',
type='comment',
),
]
formdef.store()
formdef.data_class().wipe()
resp = get_app(pub).get('/test/?param=test')
resp = resp.forms[0].submit('submit') # -> 2nd page
assert 'count with this value: 0' 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
resp = get_app(pub).get('/test/?param=test')
resp = resp.forms[0].submit('submit') # -> 2nd page
assert 'count with this value: 1' 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
resp = get_app(pub).get('/test/?param=plop')
resp = resp.forms[0].submit('submit') # -> 2nd page
assert 'count with this value: 0' in resp.text

View File

@ -139,7 +139,7 @@ def pickle_2to3_conversion(obj):
class Criteria:
def __init__(self, attribute, value):
def __init__(self, attribute, value, **kwargs):
self.attribute = attribute
self.value = value
# Python 3 requires comparisons to disparate types, this means we need
@ -152,6 +152,7 @@ class Criteria:
self.typed_none = -sys.maxsize
elif isinstance(self.value, time.struct_time):
self.typed_none = time.gmtime(-(10 ** 10)) # 1653
self.field = kwargs.get('field')
def build_lambda(self):
return lambda x: self.op(getattr(x, self.attribute, None) or self.typed_none, self.value)

View File

@ -106,9 +106,13 @@ class Criteria(qommon.storage.Criteria):
def __init__(self, attribute, value, **kwargs):
self.attribute = attribute.replace('-', '_')
self.value = value
self.field = kwargs.get('field')
def as_sql(self):
return '%s %s %%(c%s)s' % (self.attribute, self.sql_op, id(self.value))
attribute = self.attribute
if self.field and self.field.key == 'computed':
attribute = "%s->>'data'" % self.attribute
return '%s %s %%(c%s)s' % (attribute, self.sql_op, id(self.value))
def as_sql_param(self):
if isinstance(self.value, datetime.date):

View File

@ -199,9 +199,9 @@ class LazyFormDefObjectsManager:
field_id = sql.get_field_id(field)
if exclude:
criterias = NotEqual(field_id, value)
criterias = NotEqual(field_id, value, field=field)
else:
criterias = Equal(field_id, value)
criterias = Equal(field_id, value, field=field)
return self._clone(self._criterias + [criterias])
def apply_exclude_value(self, value):