diff --git a/wagtail/core/blocks/stream_block.py b/wagtail/core/blocks/stream_block.py index 5c414a4fe6..3fd933033d 100644 --- a/wagtail/core/blocks/stream_block.py +++ b/wagtail/core/blocks/stream_block.py @@ -1,4 +1,5 @@ import uuid +import warnings from collections import OrderedDict, defaultdict from collections.abc import MutableSequence @@ -14,6 +15,7 @@ from django.utils.translation import gettext as _ from wagtail.admin.staticfiles import versioned_static from wagtail.core.utils import escape_script +from wagtail.utils.deprecation import RemovedInWagtail214Warning from .base import Block, BoundBlock, DeclarativeSubBlocksMetaclass from .utils import indent, js_dict @@ -421,6 +423,12 @@ class StreamValue(MutableSequence): 'id': self.id, } + def _as_tuple(self): + if self.id: + return (self.block.name, self.value, self.id) + else: + return (self.block.name, self.value) + class RawDataView(MutableSequence): """ Internal helper class to present the stream data in raw JSONish format. For backwards @@ -460,6 +468,38 @@ class StreamValue(MutableSequence): def __repr__(self): return repr(list(self)) + class TupleView(MutableSequence): + """ + RemovedInWagtail214Warning: + Internal helper class to replicate the old behaviour of StreamValue.stream_data on a + non-lazy StreamValue. This only exists for backwards compatibility and can be dropped + once stream_data has been retired. + """ + def __init__(self, stream_value): + self.stream_value = stream_value + + def __getitem__(self, i): + # convert BoundBlock to tuple representation on retrieval + return self.stream_value[i]._as_tuple() + + # all other methods can be proxied directly to StreamValue, since its assignment / + # insertion methods accept the tuple representation + + def __len__(self): + return len(self.stream_value) + + def __setitem__(self, i, item): + self.stream_value[i] = item + + def __delitem__(self, i): + del self.stream_value[i] + + def insert(self, i, item): + self.stream_value.insert(i, item) + + def __repr__(self): + return repr(list(self)) + def __init__(self, stream_block, stream_data, is_lazy=False, raw_text=None): """ Construct a StreamValue linked to the given StreamBlock, @@ -536,6 +576,19 @@ class StreamValue(MutableSequence): def raw_data(self): return StreamValue.RawDataView(self) + @cached_property + def stream_data(self): + warnings.warn( + "The stream_data property of StreamField / StreamBlock values is deprecated.\n" + "HINT: Instead of value.stream_data[i], retrieve block objects with value[i] " + "or access the raw JSON-like data via value.raw_data[i].", + RemovedInWagtail214Warning + ) + if self.is_lazy: + return StreamValue.RawDataView(self) + else: + return StreamValue.TupleView(self) + def _prefetch_blocks(self, type_name): """ Populate _bound_blocks with all items in this stream of type `type_name` that exist in