diff --git a/wagtail/api/v2/serializers.py b/wagtail/api/v2/serializers.py index 896a3ee812..e44f56957e 100644 --- a/wagtail/api/v2/serializers.py +++ b/wagtail/api/v2/serializers.py @@ -225,7 +225,7 @@ class StreamField(Field): foreign objects are nested objects with id and meta as attributes. """ def to_representation(self, value): - return value.stream_block.get_prep_value(value) + return value.stream_block.get_api_representation(value, self.context) class TagsField(Field): diff --git a/wagtail/api/v2/tests/test_pages.py b/wagtail/api/v2/tests/test_pages.py index d8b70107e8..ceb8c24c0c 100644 --- a/wagtail/api/v2/tests/test_pages.py +++ b/wagtail/api/v2/tests/test_pages.py @@ -1025,6 +1025,18 @@ class TestPageDetailWithStreamField(TestCase): # ForeignKeys in a StreamField shouldn't be translated into dictionary representation self.assertEqual(content['body'], [{'type': 'image', 'value': 1}]) + def test_image_block_with_custom_get_api_representation(self): + stream_page = self.make_stream_page('[{"type": "image", "value": 1}]') + + response_url = '{}?extended=1'.format( + reverse('wagtailapi_v2:pages:detail', args=(stream_page.id, )) + ) + response = self.client.get(response_url) + content = json.loads(response.content.decode('utf-8')) + + # the custom get_api_representation returns a dict of id and title for the image + self.assertEqual(content['body'], [{'type': 'image', 'value': {'id': 1, 'title': 'A missing image'}}]) + @override_settings( WAGTAILFRONTENDCACHE={ diff --git a/wagtail/tests/testapp/migrations/0013_auto_20161220_1957.py b/wagtail/tests/testapp/migrations/0013_auto_20161220_1957.py new file mode 100644 index 0000000000..e3f6e443df --- /dev/null +++ b/wagtail/tests/testapp/migrations/0013_auto_20161220_1957.py @@ -0,0 +1,23 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.4 on 2016-12-20 10:57 +from __future__ import unicode_literals + +from django.db import migrations +import wagtail.tests.testapp.models +import wagtail.wagtailcore.blocks +import wagtail.wagtailcore.fields + + +class Migration(migrations.Migration): + + dependencies = [ + ('tests', '0012_panelsettings_tabbedsettings'), + ] + + operations = [ + migrations.AlterField( + model_name='streampage', + name='body', + field=wagtail.wagtailcore.fields.StreamField([('text', wagtail.wagtailcore.blocks.CharBlock()), ('rich_text', wagtail.wagtailcore.blocks.RichTextBlock()), ('image', wagtail.tests.testapp.models.ExtendedImageChooserBlock())]), + ), + ] diff --git a/wagtail/tests/testapp/models.py b/wagtail/tests/testapp/models.py index 641d98df24..f984200e54 100644 --- a/wagtail/tests/testapp/models.py +++ b/wagtail/tests/testapp/models.py @@ -638,11 +638,27 @@ class StreamModel(models.Model): ]) +class ExtendedImageChooserBlock(ImageChooserBlock): + """ + Example of Block with custom get_api_representation method. + If the request has an 'extended' query param, it returns a dict of id and title, + otherwise, it returns the default value. + """ + def get_api_representation(self, value, context=None): + image_id = super(ExtendedImageChooserBlock, self).get_api_representation(value, context=context) + if 'request' in context and context['request'].query_params.get('extended', False): + return { + 'id': image_id, + 'title': value.title + } + return image_id + + class StreamPage(Page): body = StreamField([ ('text', CharBlock()), ('rich_text', RichTextBlock()), - ('image', ImageChooserBlock()), + ('image', ExtendedImageChooserBlock()), ]) api_fields = ('body',) diff --git a/wagtail/wagtailcore/blocks/base.py b/wagtail/wagtailcore/blocks/base.py index 17e8f8d25d..1531762983 100644 --- a/wagtail/wagtailcore/blocks/base.py +++ b/wagtail/wagtailcore/blocks/base.py @@ -257,6 +257,12 @@ class Block(six.with_metaclass(BaseBlock, object)): return mark_safe(render_to_string(template, new_context)) + def get_api_representation(self, value, context=None): + """ + Can be used to customise the API response and defaults to the value returned by get_prep_value. + """ + return self.get_prep_value(value) + def render_basic(self, value, context=None): """ Return a text rendering of 'value', suitable for display on templates. render() will fall back on diff --git a/wagtail/wagtailcore/blocks/list_block.py b/wagtail/wagtailcore/blocks/list_block.py index 7e940100b9..f12e4d0b84 100644 --- a/wagtail/wagtailcore/blocks/list_block.py +++ b/wagtail/wagtailcore/blocks/list_block.py @@ -143,6 +143,13 @@ class ListBlock(Block): for item in value ] + def get_api_representation(self, value, context=None): + # recursively call get_api_representation on children and return as a list + return [ + self.child_block.get_api_representation(item, context=context) + for item in value + ] + def render_basic(self, value, context=None): children = format_html_join( '\n', '