fields: add support for card data sources to computed fields (#58913)
This commit is contained in:
parent
92d7530f83
commit
9af4b3952f
|
@ -5,6 +5,7 @@ import pytest
|
|||
from django.utils.timezone import make_aware
|
||||
|
||||
from wcs import fields
|
||||
from wcs.carddef import CardDef
|
||||
from wcs.formdef import FormDef
|
||||
from wcs.qommon.substitution import CompatibilityNamesDict
|
||||
from wcs.workflows import EditableWorkflowStatusItem, Workflow
|
||||
|
@ -586,3 +587,49 @@ def test_computed_field_usage_in_criteria(pub):
|
|||
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
|
||||
|
||||
|
||||
def test_computed_field_with_data_source(pub):
|
||||
CardDef.wipe()
|
||||
FormDef.wipe()
|
||||
|
||||
carddef = CardDef()
|
||||
carddef.name = 'items'
|
||||
carddef.digest_templates = {'default': '{{form_var_name}}'}
|
||||
carddef.fields = [
|
||||
fields.StringField(id='0', label='string', varname='name'),
|
||||
fields.StringField(id='1', label='string', varname='attr'),
|
||||
]
|
||||
carddef.store()
|
||||
for i, value in enumerate(['foo', 'bar', 'baz']):
|
||||
carddata = carddef.data_class()()
|
||||
carddata.data = {
|
||||
'0': value,
|
||||
'1': 'attr%s' % i,
|
||||
}
|
||||
carddata.just_created()
|
||||
carddata.store()
|
||||
|
||||
ds = {'type': 'carddef:%s' % carddef.url_name}
|
||||
|
||||
formdef = FormDef()
|
||||
formdef.name = 'test'
|
||||
formdef.fields = [
|
||||
fields.ComputedField(
|
||||
id='1',
|
||||
label='computed',
|
||||
varname='computed',
|
||||
value_template='{{ request.GET.param }}',
|
||||
freeze_on_initial_value=True,
|
||||
data_source=ds,
|
||||
),
|
||||
fields.CommentField(id='2', label='X{{ form_var_computed_live_var_name }}Y', type='comment'),
|
||||
]
|
||||
formdef.store()
|
||||
formdef.data_class().wipe()
|
||||
|
||||
resp = get_app(pub).get('/test/?param=%s' % carddata.id)
|
||||
assert 'XbazY' in resp.text
|
||||
|
||||
resp = get_app(pub).get('/test/?param=%s' % 'invalid')
|
||||
assert 'XY' in resp.text
|
||||
|
|
|
@ -3484,6 +3484,7 @@ class ComputedField(Field):
|
|||
|
||||
value_template = None
|
||||
freeze_on_initial_value = False
|
||||
data_source = {}
|
||||
|
||||
add_to_form = None
|
||||
add_to_view_form = None
|
||||
|
@ -3497,7 +3498,7 @@ class ComputedField(Field):
|
|||
def get_admin_attributes(self):
|
||||
attributes = super().get_admin_attributes()
|
||||
attributes.remove('condition')
|
||||
return attributes + ['varname', 'value_template', 'freeze_on_initial_value']
|
||||
return attributes + ['varname', 'value_template', 'freeze_on_initial_value', 'data_source']
|
||||
|
||||
def fill_admin_form(self, form):
|
||||
form.add(StringWidget, 'label', title=_('Label'), value=self.label, required=True, size=50)
|
||||
|
@ -3526,6 +3527,18 @@ class ComputedField(Field):
|
|||
title=_('Freeze on initial value'),
|
||||
value=self.freeze_on_initial_value,
|
||||
)
|
||||
form.add(
|
||||
data_sources.DataSourceSelectionWidget,
|
||||
'data_source',
|
||||
value=self.data_source,
|
||||
allow_jsonp=False,
|
||||
title=_('Data Source'),
|
||||
hint=_('This will make linked card data available for expressions.'),
|
||||
required=False,
|
||||
)
|
||||
|
||||
def get_real_data_source(self):
|
||||
return data_sources.get_real(self.data_source)
|
||||
|
||||
|
||||
register_field_class(ComputedField)
|
||||
|
|
|
@ -844,49 +844,7 @@ class LazyFieldVarComplex(LazyFieldVar):
|
|||
raise KeyError(key)
|
||||
|
||||
|
||||
class LazyFieldVarComputed(LazyFieldVarComplex):
|
||||
def get_field_var_value(self):
|
||||
return self.get_value()
|
||||
|
||||
|
||||
class LazyFieldVarStructured(LazyFieldVarComplex):
|
||||
def inspect_keys(self):
|
||||
if not self._data.get(self._field.id):
|
||||
return []
|
||||
real_data_source = self._field.get_real_data_source()
|
||||
if real_data_source and real_data_source.get('type', '') == 'wcs:users':
|
||||
return ['raw', 'live']
|
||||
|
||||
structured_value = self._field.get_structured_value(self._data)
|
||||
if not structured_value:
|
||||
return ['raw']
|
||||
|
||||
keys = ['raw', 'structured']
|
||||
if real_data_source and real_data_source.get('type', '').startswith('carddef:'):
|
||||
try:
|
||||
self.live
|
||||
except AttributeError:
|
||||
# don't advertise "live" if linked data is missing
|
||||
pass
|
||||
else:
|
||||
keys.append('live')
|
||||
|
||||
keys.extend(super().inspect_keys())
|
||||
|
||||
return keys
|
||||
|
||||
@property
|
||||
def structured_raw(self):
|
||||
# backward compatibility, _structured should be use.
|
||||
return self._field.get_structured_value(self._data)
|
||||
|
||||
@property
|
||||
def structured(self):
|
||||
return self._field.get_structured_value(self._data)
|
||||
|
||||
def get_field_var_value(self):
|
||||
return self.structured
|
||||
|
||||
class LazyFieldVarLiveCardMixin:
|
||||
@property
|
||||
def live(self):
|
||||
real_data_source = self._field.get_real_data_source()
|
||||
|
@ -928,6 +886,60 @@ class LazyFieldVarStructured(LazyFieldVarComplex):
|
|||
return LazyFormData(carddata)
|
||||
|
||||
|
||||
class LazyFieldVarComputed(LazyFieldVarComplex, LazyFieldVarLiveCardMixin):
|
||||
def inspect_keys(self):
|
||||
keys = super().inspect_keys()
|
||||
try:
|
||||
self.live
|
||||
except AttributeError:
|
||||
pass # don't advertise if there's no value behind
|
||||
else:
|
||||
keys.append('live')
|
||||
return keys
|
||||
|
||||
def get_field_var_value(self):
|
||||
return self.get_value()
|
||||
|
||||
|
||||
class LazyFieldVarStructured(LazyFieldVarComplex, LazyFieldVarLiveCardMixin):
|
||||
def inspect_keys(self):
|
||||
if not self._data.get(self._field.id):
|
||||
return []
|
||||
real_data_source = self._field.get_real_data_source()
|
||||
if real_data_source and real_data_source.get('type', '') == 'wcs:users':
|
||||
return ['raw', 'live']
|
||||
|
||||
structured_value = self._field.get_structured_value(self._data)
|
||||
if not structured_value:
|
||||
return ['raw']
|
||||
|
||||
keys = ['raw', 'structured']
|
||||
if real_data_source and real_data_source.get('type', '').startswith('carddef:'):
|
||||
try:
|
||||
self.live
|
||||
except AttributeError:
|
||||
# don't advertise "live" if linked data is missing
|
||||
pass
|
||||
else:
|
||||
keys.append('live')
|
||||
|
||||
keys.extend(super().inspect_keys())
|
||||
|
||||
return keys
|
||||
|
||||
@property
|
||||
def structured_raw(self):
|
||||
# backward compatibility, _structured should be use.
|
||||
return self._field.get_structured_value(self._data)
|
||||
|
||||
@property
|
||||
def structured(self):
|
||||
return self._field.get_structured_value(self._data)
|
||||
|
||||
def get_field_var_value(self):
|
||||
return self.structured
|
||||
|
||||
|
||||
class DateOperatorsMixin:
|
||||
def __eq__(self, other):
|
||||
if hasattr(other, 'timetuple'):
|
||||
|
|
Loading…
Reference in New Issue