问题
I have a few questions about this thread: https://groups.google.com/forum/#!topic/wagtail-developers/Z4oaCIJXYuI
I am building a headless Wagtail, with a React-based frontend, that calls Wagtail API in order to parse JSON and display content. Pretty basic.
I was wondering if it was possible to custom the output of streamfield in rest API. A few examples:
- Get a image URL based on this example from wagtaildemo: https://github.com/wagtail/wagtaildemo/blob/api-tweaks/demo/models.py#L713-L716 (I got it working for single URLs)
- PageChooserBlock: get a field from the targetted page
As I read in the topic linked above, the Wagtail API v1 was not ready for custom representation of Streamfield in it. Did it change since v2 ? (I didn't notice anything related in changelogs) If not, does anyone have some tips about how I could achieve such a thing?
I already planned on build a custom image model to get URL by calling api/v2/images/id
, but I would love to get all these into one JSON response 🤘.
回答1:
As of Wagtail 1.9, you can modify the API representation of the Block in the StreamField by overriding the get_api_representation()
method on the Block.
For your example we can override the method on the ImageChooserBlock itself:
class ImageSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = wagtail.wagtailimages.get_image_model()
fields = ['title', 'file', 'width', 'height', 'file_size']
class APIImageChooserBlock(ImageChooserBlock):
def get_api_representation(self, value, context=None):
return ImageSerializer(context=context).to_representation(value)
@wagtail.wagtailsnippets.models.register_snippet
class MySnippetForAPI(models.Model):
title = models.CharField(max_length=80)
content = StreamField([
('heading', blocks.CharBlock()),
('paragraph', blocks.RichTextBlock()),
('image', APIImageChooserBlock())
])
https://github.com/wagtail/wagtail/blob/b6ee2db6ac8dbf4b47a81f4b2684b7aca8cc2501/wagtail/wagtailcore/blocks/base.py#L244
回答2:
This isn't a direct answer to your question but the NHS content store app is solving similar problems and may be a useful reference:
https://github.com/nhsuk/nhsuk-content-store
in particular
https://github.com/nhsuk/nhsuk-content-store/blob/master/api/serializers.py
回答3:
Adding onto the very helpful answer by probabble, you can also use get_rendition inside a StreamField block by adding a SerializerMethodField
:
# serializers.py
# Explicitly importing since models are not loaded when serializers initialized
from wagtail.wagtailimages.models import Image as WagtailImage
class WagtailImageSerializer(serializers.ModelSerializer):
url = serializers.SerializerMethodField()
class Meta:
model = WagtailImage
fields = ['title', 'url']
def get_url(self, obj):
return obj.get_rendition('fill-300x186|jpegquality-60').url
# blocks.py
from .serializers import WagtailImageSerializer
class APIImageChooserBlock(ImageChooserBlock):
def get_api_representation(self, value, context=None):
return WagtailImageSerializer(context=context).to_representation(value)
In this example, we only return the title and url of the image.
来源:https://stackoverflow.com/questions/41956709/custom-representation-of-streamfield-in-rest-api