Support slicing on StreamValue (#7013)

Fixes #7012
pull/6998/head
Matt Westcott 2021-04-15 18:37:07 +01:00
rodzic ca48709e5c
commit 02ad797673
4 zmienionych plików z 35 dodań i 0 usunięć

Wyświetl plik

@ -22,6 +22,7 @@ Changelog
* Add a new switch input widget as an alternative to checkboxes (Karl Hobley)
* Allow `{% pageurl %}` fallback to be a direct URL or an object with a `get_absolute_url` method (Andy Babic)
* Add support for exporting redirects (Martin Sandström)
* Support slicing on StreamField / StreamBlock values (Matt Westcott)
* Fix: StreamField required status is now consistently handled by the `blank` keyword argument (Matt Westcott)
* Fix: Show 'required' asterisks for blocks inside required StreamFields (Matt Westcott)
* Fix: Make image chooser "Select format" fields translatable (Helen Chapman, Thibaud Colas)

Wyświetl plik

@ -45,6 +45,8 @@ Other features
* Add a new switch input widget as an alternative to checkboxes (Karl Hobley)
* Allow ``{% pageurl %}`` fallback to be a direct URL or an object with a ``get_absolute_url`` method (Andy Babic)
* Add support for exporting redirects (Martin Sandström)
* Support slicing on StreamField / StreamBlock values (Matt Westcott)
Bug fixes
~~~~~~~~~

Wyświetl plik

@ -505,6 +505,10 @@ class StreamValue(MutableSequence):
return StreamValue.StreamChild(block_def, value, id=block_id)
def __getitem__(self, i):
if isinstance(i, slice):
start, stop, step = i.indices(len(self._bound_blocks))
return [self[j] for j in range(start, stop, step)]
if self._bound_blocks[i] is None:
raw_value = self._raw_data[i]
self._prefetch_blocks(raw_value['type'])

Wyświetl plik

@ -27,6 +27,11 @@ class TestLazyStreamField(TestCase):
self.no_image = StreamModel.objects.create(body=json.dumps([
{'type': 'text', 'value': 'foo'}]))
self.nonjson_body = StreamModel.objects.create(body="<h1>hello world</h1>")
self.three_items = StreamModel.objects.create(body=json.dumps([
{'type': 'text', 'value': 'foo'},
{'type': 'image', 'value': self.image.pk},
{'type': 'text', 'value': 'bar'},
]))
def test_lazy_load(self):
"""
@ -50,6 +55,29 @@ class TestLazyStreamField(TestCase):
self.assertEqual(body[0].value, self.image)
self.assertEqual(body[1].value, 'foo')
def test_slice(self):
with self.assertNumQueries(1):
instance = StreamModel.objects.get(pk=self.three_items.pk)
with self.assertNumQueries(1):
# Access the image item from the stream. The image is fetched now
instance.body[1].value
with self.assertNumQueries(0):
# taking a slice of a StreamValue should re-use already-fetched values
values = [block.value for block in instance.body[1:3]]
self.assertEqual(values, [self.image, 'bar'])
with self.assertNumQueries(0):
# test slicing with negative indexing
values = [block.value for block in instance.body[-2:]]
self.assertEqual(values, [self.image, 'bar'])
with self.assertNumQueries(0):
# test slicing with skips
values = [block.value for block in instance.body[0:3:2]]
self.assertEqual(values, ['foo', 'bar'])
def test_lazy_load_no_images(self):
"""
Getting a single item whose StreamField never accesses the database