In previous tutorials we've learned how to enable the Wagtail v2 API so we can create a headless CMS, we learned how to expose our custom model fields, and we learned how to fetch specific fields from the API using only our URL bar.
But we didn't learn how to expose StreamFields or custom model fields from inside an Orderable.
In this video we'll learn how to do both of these.
StreamFields in your API
Enabling StreamField API output is super simple. It's a subject I forgot to cover in an early lesson, but it's so simple we can cover this at any point in time because it's the exact same as exposing a custom model field, which we have explored in depth already.
from wagtail.api import APIField from wagtail.core.fields import StreamField from wagtail.core.models import Page from streams import blocks class YourWagtailPage(Page): # These are your StreamFields. Adjust this as field as needed. content = StreamField( [ ("title_and_text", blocks.TitleAndTextBlock()), ("full_richtext", blocks.RichtextBlock()), ("simple_richtext", blocks.SimpleRichtextBlock()), ("cards", blocks.CardBlock()), ("cta", blocks.CTABlock()), ], null=True, blank=True, ) # Exposing your StreamField() api_fields = [ APIField("content"), ]
Orderables in your API
Adding an Orderable to your API output is a bit more work, but honestly it's not very much work either. The main thing to note is that you need to add
api_fields to your main Page model, and also your Orderable.
By adding api_fields to your Page model, you're telling the API to link to the Orderable. But by default the Orderable does not have custom fields exposed, so we need to expose them by adding
api_fields to the Orderable. A blog-based example can be found below (or view the gist for a quick overview)
from django.db import models from modelcluster.fields import ParentalKey from wagtail.api import APIField from wagtail.admin.edit_handlers import FieldPanel, StreamFieldPanel from wagtail.core.fields import StreamField from wagtail.core.models import Page, Orderable from wagtail.snippets.edit_handlers import SnippetChooserPanel from wagtail.snippets.models import register_snippet from streams import blocks class BlogAuthorsOrderable(Orderable): """This allows us to select one or more blog authors from Snippets.""" page = ParentalKey("blog.BlogDetailPage", related_name="blog_authors") author = models.ForeignKey( "blog.BlogAuthor", on_delete=models.CASCADE, ) panels = [ SnippetChooserPanel("author"), ] @property # Traverse through the `author` ForeignKey to return the `name` def author_name(self): return self.author.name @property # Traverse through the `author` ForeignKey to return the `website` def author_website(self): return self.author.website # Expose author_name and author_website fields # These are now properties in our Orderable. api_fields = [ APIField("author_name"), APIField("author_website"), ] @register_snippet class BlogAuthor(models.Model): """Blog author snippets.""" name = models.CharField(max_length=100) website = models.URLField(blank=True, null=True) panels = [ FieldPanel("name"), FieldPanel("website"), ] def __str__(self): """String repr of this class.""" return self.name class Meta: # noqa verbose_name = "Blog Author" verbose_name_plural = "Blog Authors" class BlogDetailPage(Page): """Blog detail page.""" # StreamFields. Adjust this field as needed. content = StreamField( [ ("title_and_text", blocks.TitleAndTextBlock()), ("full_richtext", blocks.RichtextBlock()), ("simple_richtext", blocks.SimpleRichtextBlock()), ("cards", blocks.CardBlock()), ("cta", blocks.CTABlock()), ], null=True, blank=True, ) content_panels = Page.content_panels + [ StreamFieldPanel("content"), ] api_fields = [ # Exposed the related_name from the BlogAuthorsOrderable APIField("blog_authors"), # Exposed StreamFields APIField("content"), ]