mirror of
https://github.com/Hopiu/wagtail.git
synced 2026-05-12 09:13:14 +00:00
Refactor StreamValue so that it behaves as a sequence of BoundBlocks rather than a sequence of values
This commit is contained in:
parent
2a485e499e
commit
94a248055b
1 changed files with 31 additions and 31 deletions
|
|
@ -660,9 +660,9 @@ class BaseStreamBlock(Block):
|
|||
|
||||
def render_form(self, value, prefix='', error=None):
|
||||
list_members_html = [
|
||||
self.render_list_member(block_type, child_value, "%s-%d" % (prefix, i), i,
|
||||
self.render_list_member(child.block.name, child.value, "%s-%d" % (prefix, i), i,
|
||||
error=error.params[i] if error else None)
|
||||
for (i, (child_value, block_type)) in enumerate(value.values_with_types)
|
||||
for (i, child) in enumerate(value)
|
||||
]
|
||||
|
||||
return render_to_string('wagtailadmin/block_forms/stream.html', {
|
||||
|
|
@ -685,22 +685,24 @@ class BaseStreamBlock(Block):
|
|||
values_with_indexes.append(
|
||||
(
|
||||
data['%s-%d-order' % (prefix, i)],
|
||||
child_block.value_from_datadict(data, files, '%s-%d-value' % (prefix, i)),
|
||||
block_type_name,
|
||||
child_block.value_from_datadict(data, files, '%s-%d-value' % (prefix, i)),
|
||||
)
|
||||
)
|
||||
|
||||
values_with_indexes.sort()
|
||||
return StreamValue(self, [(val, typ) for (index, val, typ) in values_with_indexes])
|
||||
return StreamValue(self, [
|
||||
(block_type_name, value)
|
||||
for (index, block_type_name, value) in values_with_indexes
|
||||
])
|
||||
|
||||
def clean(self, value):
|
||||
result = []
|
||||
cleaned_data = []
|
||||
errors = []
|
||||
for child_type, child_val in value.values_with_types:
|
||||
child_block = self.child_blocks[child_type]
|
||||
for child in value: # child is a BoundBlock instance
|
||||
try:
|
||||
result.append(
|
||||
(child_block.clean(child_val), child_type)
|
||||
cleaned_data.append(
|
||||
(child.block.clean(child.value), child.block.name)
|
||||
)
|
||||
except ValidationError as e:
|
||||
errors.append(e)
|
||||
|
|
@ -712,14 +714,14 @@ class BaseStreamBlock(Block):
|
|||
# which only involves the 'params' list
|
||||
raise ValidationError('Validation error in StreamBlock', params=errors)
|
||||
|
||||
return StreamValue(self, result)
|
||||
return StreamValue(self, cleaned_data)
|
||||
|
||||
def to_python(self, value):
|
||||
# the incoming JSONish representation is a list of dicts, each with a 'type' and 'value' field.
|
||||
# Convert this to a StreamValue backed by a list of (value, type) tuples
|
||||
# Convert this to a StreamValue backed by a list of (type, value) tuples
|
||||
return StreamValue(self, [
|
||||
(self.child_blocks[item['type']].to_python(item['value']), item['type'])
|
||||
for item in value
|
||||
(child_data['type'], self.child_blocks[child_data['type']].to_python(child_data['value']))
|
||||
for child_data in value
|
||||
])
|
||||
|
||||
def get_prep_value(self, value):
|
||||
|
|
@ -727,13 +729,13 @@ class BaseStreamBlock(Block):
|
|||
return None
|
||||
|
||||
return [
|
||||
{'type': bound_block.block.name, 'value': bound_block.block.get_prep_value(bound_block.value)}
|
||||
for bound_block in value.bound_blocks
|
||||
{'type': child.block.name, 'value': child.block.get_prep_value(child.value)}
|
||||
for child in value # child is a BoundBlock instance
|
||||
]
|
||||
|
||||
def render(self, value):
|
||||
return format_html_join('\n', '<div class="block-{1}">{0}</div>',
|
||||
[(bound_block.render(), bound_block.block.name) for bound_block in value.bound_blocks]
|
||||
[(child.render(), child.block.name) for child in value]
|
||||
)
|
||||
|
||||
|
||||
|
|
@ -744,29 +746,27 @@ class StreamBlock(six.with_metaclass(DeclarativeSubBlocksMetaclass, BaseStreamBl
|
|||
@python_2_unicode_compatible # provide equivalent __unicode__ and __str__ methods on Py2
|
||||
class StreamValue(collections.Sequence):
|
||||
"""
|
||||
Custom type used to represent the value of a StreamBlock; behaves as a sequence of block values
|
||||
so that we can naturally iterate over it in template code, but also allows retrieval of
|
||||
(value, type) tuples as required for the form (and other complex rendering logic) to work.
|
||||
Custom type used to represent the value of a StreamBlock; behaves as a sequence of BoundBlocks
|
||||
(which keep track of block types in a way that the values alone wouldn't).
|
||||
"""
|
||||
def __init__(self, stream_block, values_with_types):
|
||||
self.stream_block = stream_block
|
||||
self.values_with_types = values_with_types
|
||||
def __init__(self, stream_block, stream_data):
|
||||
self.stream_block = stream_block # the StreamBlock object that handles this value
|
||||
self.stream_data = stream_data # a list of (type_name, value) tuples
|
||||
self._bound_blocks = {} # populated lazily from stream_data as we access items through __getitem__
|
||||
|
||||
def __getitem__(self, i):
|
||||
return self.values_with_types[i][0]
|
||||
if i not in self._bound_blocks:
|
||||
type_name, value = self.stream_data[i]
|
||||
child_block = self.stream_block.child_blocks[type_name]
|
||||
self._bound_blocks[i] = child_block.bind(value)
|
||||
|
||||
return self._bound_blocks[i]
|
||||
|
||||
def __len__(self):
|
||||
return len(self.values_with_types)
|
||||
return len(self.stream_data)
|
||||
|
||||
def __repr__(self):
|
||||
return repr(list(self))
|
||||
|
||||
def __str__(self):
|
||||
return self.stream_block.render(self)
|
||||
|
||||
@cached_property
|
||||
def bound_blocks(self):
|
||||
return [
|
||||
BoundBlock(self.stream_block.child_blocks[block_type], value)
|
||||
for value, block_type in self.values_with_types
|
||||
]
|
||||
|
|
|
|||
Loading…
Reference in a new issue