diff --git a/wagtail/core/blocks/list_block.py b/wagtail/core/blocks/list_block.py index 4d08065f32..9c9f80a8cb 100644 --- a/wagtail/core/blocks/list_block.py +++ b/wagtail/core/blocks/list_block.py @@ -146,9 +146,11 @@ class ListBlock(Block): result = [] errors = [] non_block_errors = ErrorList() - for child_val in value: + for bound_block in value.bound_blocks: try: - result.append(self.child_block.clean(child_val)) + result.append(ListValue.ListChild( + self.child_block, self.child_block.clean(bound_block.value), id=bound_block.id + )) except ValidationError as e: errors.append(ErrorList([e])) else: @@ -167,7 +169,7 @@ class ListBlock(Block): if any(errors) or non_block_errors: raise ListBlockValidationError(block_errors=errors, non_block_errors=non_block_errors) - return ListValue(self, values=result) + return ListValue(self, bound_blocks=result) def _item_is_in_block_format(self, item): # check a list item retrieved from the database JSON representation to see whether it follows diff --git a/wagtail/core/tests/test_blocks.py b/wagtail/core/tests/test_blocks.py index 7f17a25527..f2e2061928 100644 --- a/wagtail/core/tests/test_blocks.py +++ b/wagtail/core/tests/test_blocks.py @@ -2382,31 +2382,44 @@ class TestListBlock(WagtailTestUtils, SimpleTestCase): }, }) + def test_clean_preserves_block_ids(self): + block = blocks.ListBlock(blocks.CharBlock()) + block_val = block.to_python([ + {'type': 'item', 'value': 'foo', 'id': '11111111-1111-1111-1111-111111111111'}, + {'type': 'item', 'value': 'bar', 'id': '22222222-2222-2222-2222-222222222222'}, + ]) + cleaned_block_val = block.clean(block_val) + self.assertEqual(cleaned_block_val.bound_blocks[0].id, '11111111-1111-1111-1111-111111111111') + def test_min_num_validation_errors(self): block = blocks.ListBlock(blocks.CharBlock(), min_num=2) + block_val = block.to_python(['foo']) with self.assertRaises(ValidationError) as catcher: - block.clean(['foo']) + block.clean(block_val) self.assertEqual(catcher.exception.params, { 'block_errors': [None], 'non_block_errors': ['The minimum number of items is 2'] }) # a value with >= 2 blocks should pass validation - self.assertTrue(block.clean(['foo', 'bar'])) + block_val = block.to_python(['foo', 'bar']) + self.assertTrue(block.clean(block_val)) def test_max_num_validation_errors(self): block = blocks.ListBlock(blocks.CharBlock(), max_num=2) + block_val = block.to_python(['foo', 'bar', 'baz']) with self.assertRaises(ValidationError) as catcher: - block.clean(['foo', 'bar', 'baz']) + block.clean(block_val) self.assertEqual(catcher.exception.params, { 'block_errors': [None, None, None], 'non_block_errors': ['The maximum number of items is 2'] }) # a value with <= 2 blocks should pass validation - self.assertTrue(block.clean(['foo', 'bar'])) + block_val = block.to_python(['foo', 'bar']) + self.assertTrue(block.clean(block_val)) def test_unpack_old_database_format(self): block = blocks.ListBlock(blocks.CharBlock())