misc: add actual prefill support for multiple choices widgets (#76568) #668
|
@ -573,7 +573,10 @@ def test_form_page_date_prefill(pub):
|
|||
assert resp.forms[0]['f0'].value == '2023-07-07'
|
||||
|
||||
|
||||
def test_form_page_template_prefill_items_field(pub):
|
||||
@pytest.mark.parametrize('prefill_value', ['foo,baz', 'foo|baz'])
|
||||
def test_form_page_template_prefill_items_field_checkboxes(pub, prefill_value):
|
||||
# prefill value should be given as foo|baz but foo,baz has been used for a while
|
||||
# and must be kept working (even if it worked by chance).
|
||||
BlockDef.wipe()
|
||||
create_user(pub)
|
||||
|
||||
|
@ -591,7 +594,7 @@ def test_form_page_template_prefill_items_field(pub):
|
|||
id='0',
|
||||
label='items',
|
||||
items=['foo', 'bar', 'baz'],
|
||||
prefill={'type': 'string', 'value': 'foo,baz'},
|
||||
prefill={'type': 'string', 'value': prefill_value},
|
||||
),
|
||||
fields.FileField(id='1', label='file', varname='file'),
|
||||
fields.BlockField(id='2', label='test', block_slug='foobar', varname='foobar'),
|
||||
|
@ -619,7 +622,7 @@ def test_form_page_template_prefill_items_field(pub):
|
|||
label='items',
|
||||
data_source=ds,
|
||||
display_disabled_items=True,
|
||||
prefill={'type': 'string', 'value': 'foo,baz'},
|
||||
prefill={'type': 'string', 'value': prefill_value},
|
||||
)
|
||||
formdef.store()
|
||||
|
||||
|
@ -708,6 +711,135 @@ def test_form_page_template_prefill_items_field(pub):
|
|||
assert pub.loggederror_class.count() == 0
|
||||
|
||||
|
||||
def test_form_page_template_prefill_items_field_autocomplete(pub):
|
||||
BlockDef.wipe()
|
||||
create_user(pub)
|
||||
|
||||
block = BlockDef()
|
||||
block.name = 'foobar'
|
||||
block.fields = [
|
||||
fields.StringField(id='123', required=True, label='Test', varname='test'),
|
||||
]
|
||||
block.store()
|
||||
|
||||
formdef = create_formdef()
|
||||
formdef.data_class().wipe()
|
||||
formdef.fields = [
|
||||
fields.ItemsField(
|
||||
id='0',
|
||||
label='items',
|
||||
items=['foo', 'bar', 'baz'],
|
||||
prefill={'type': 'string', 'value': 'foo|baz'},
|
||||
display_mode='autocomplete',
|
||||
),
|
||||
fields.FileField(id='1', label='file', varname='file'),
|
||||
fields.BlockField(id='2', label='test', block_slug='foobar', varname='foobar'),
|
||||
]
|
||||
formdef.store()
|
||||
|
||||
resp = get_app(pub).get('/test/')
|
||||
assert resp.form['f0[]'].value == ['foo', 'baz']
|
||||
# this selection will be reused in the complex data test
|
||||
resp.form['f0[]'].value = ['foo', 'bar']
|
||||
assert 'widget-prefilled' in resp.text
|
||||
resp.form['f1$file'] = Upload('test.txt', b'foobar', 'text/plain')
|
||||
resp.form['f2$element0$f123'] = 'plop'
|
||||
resp = resp.form.submit('submit')
|
||||
resp = resp.form.submit('submit')
|
||||
assert formdef.data_class().count() == 1
|
||||
|
||||
# check with remote json
|
||||
ds = {'type': 'json', 'value': 'http://remote.example.net/json'}
|
||||
formdef.fields[0] = fields.ItemsField(
|
||||
id='0',
|
||||
label='items',
|
||||
data_source=ds,
|
||||
display_disabled_items=True,
|
||||
prefill={'type': 'string', 'value': 'foo|baz'},
|
||||
display_mode='autocomplete',
|
||||
)
|
||||
formdef.store()
|
||||
|
||||
with responses.RequestsMock() as rsps:
|
||||
rsps.get(
|
||||
'http://remote.example.net/json',
|
||||
json={
|
||||
'data': [
|
||||
{'id': 'foo', 'text': 'hello'},
|
||||
{'id': 'bar', 'text': 'world'},
|
||||
{'id': 'baz', 'text': '!'},
|
||||
]
|
||||
},
|
||||
)
|
||||
|
||||
resp = get_app(pub).get('/test/')
|
||||
assert resp.form['f0[]'].value == ['foo', 'baz']
|
||||
|
||||
# check with template returning a complex data
|
||||
formdef.fields[0] = fields.ItemsField(
|
||||
id='0',
|
||||
varname='items',
|
||||
label='items',
|
||||
data_source=ds,
|
||||
display_disabled_items=True,
|
||||
prefill={'type': 'string', 'value': '{{form_objects|first|get:"form_var_items_raw"}}'},
|
||||
display_mode='autocomplete',
|
||||
)
|
||||
formdef.store()
|
||||
|
||||
# it will use foo,bar as selected in the first part of this test
|
||||
resp = get_app(pub).get('/test/')
|
||||
assert resp.form['f0[]'].value == ['foo', 'bar']
|
||||
|
||||
# check with complex data of wrong type
|
||||
for invalid_prefill_value in [
|
||||
{'type': 'string', 'value': '{{form_objects|first|get:"form_var_file_raw"}}'},
|
||||
{'type': 'string', 'value': '{{form_objects|first|get:"form_var_foobar"}}'},
|
||||
{'type': 'formula', 'value': '[{"a": "foo", "b": "baz"}]'},
|
||||
]:
|
||||
formdef.fields[0] = fields.ItemsField(
|
||||
id='0',
|
||||
varname='items',
|
||||
label='items',
|
||||
data_source=ds,
|
||||
display_disabled_items=True,
|
||||
prefill=invalid_prefill_value,
|
||||
display_mode='autocomplete',
|
||||
)
|
||||
formdef.store()
|
||||
|
||||
resp = get_app(pub).get('/test/')
|
||||
assert resp.form['f0[]'].value is None
|
||||
|
||||
assert pub.loggederror_class.count() == 1
|
||||
logged_error = pub.loggederror_class.select()[0]
|
||||
assert logged_error.summary == 'Invalid value for items prefill on field "items"'
|
||||
pub.loggederror_class.wipe()
|
||||
|
||||
# check with a "none" explicit prefill, or a None value
|
||||
for none_prefill_value in [
|
||||
{},
|
||||
{'type': 'none'},
|
||||
{'type': 'string', 'value': '{{ None }}'},
|
||||
{'type': 'formula', 'value': 'None'},
|
||||
]:
|
||||
formdef.fields[0] = fields.ItemsField(
|
||||
id='0',
|
||||
varname='items',
|
||||
label='items',
|
||||
data_source=ds,
|
||||
display_disabled_items=True,
|
||||
prefill=none_prefill_value,
|
||||
display_mode='autocomplete',
|
||||
)
|
||||
formdef.store()
|
||||
|
||||
# all checkboxes will be left unchecked
|
||||
resp = get_app(pub).get('/test/')
|
||||
assert resp.form['f0[]'].value is None
|
||||
assert pub.loggederror_class.count() == 0
|
||||
|
||||
|
||||
def test_form_page_changing_prefill(pub):
|
||||
formdef = create_formdef()
|
||||
formdef.data_class().wipe()
|
||||
|
|
|
@ -1789,6 +1789,12 @@ class CheckboxesWidget(Widget):
|
|||
def get_too_long_message(self):
|
||||
return _('You must select at most %d answers.') % self.max_choices
|
||||
|
||||
def set_value(self, value):
|
||||
if isinstance(value, str) and '|' in value:
|
||||
self.value = value.split('|')
|
||||
else:
|
||||
super().set_value(value)
|
||||
|
||||
def transfer_form_value(self, request):
|
||||
for v in self.value or []:
|
||||
for option in self.get_options():
|
||||
|
@ -2801,6 +2807,11 @@ class MultiSelectWidget(MultipleSelectWidget):
|
|||
def get_selected_options_labels(self):
|
||||
return list(x.get('label') for x in self.get_options() if x.get('selected'))
|
||||
|
||||
def set_value(self, value):
|
||||
if isinstance(value, str) and '|' in value:
|
||||
value = value.split('|')
|
||||
super().set_value(value)
|
||||
|
||||
def transfer_form_value(self, request):
|
||||
request.form[self.name + '[]'] = self.value
|
||||
|
||||
|
|
Loading…
Reference in New Issue