Headless Wagtail CMS: Serializing RichText Stream Blocks
Published November 29, 2023
This video features Kalob Taulien at Wagtail CMS 2023 .
LearnWagtail.comTutorial:
https://learnwagtail.com/tutorials/streamfield-deep-dive-2-exploring-common-streamfields/
Wagtail for Beginners Course: https://learnwagtail.com/wagtail-for-beginners/
StreamFields are not complicated. If you're familiar with Django Models at all, this will be super simple to understand. If you've never used a Django Model thats OK because, luckily, Python, Django and Wagtail are all very verbose (literal naming conventions) so you can pick up on what's going on without knowing Django.
We'll dive into most of the simple StreamFields and explore some of the options they have to offer. We'll also look at ChooserBlock inheritance for the PageChooserBlock, ImageChooserBlock and DocumentChooserBlock.
Wagtail StreamField Source Code: https://github.com/wagtail/wagtail/blob/master/wagtail/core/blocks/field_block.py
For more free tutorials: https://learnwagtail.com/tutorials/
Don't forget to subscribe to this channel and follow me on Twitter at https://twitter.com/kalobtaulien
Used in this video: Wagtail 2.5.1, Python 3.7, Django 2.2.2
#Wagtail #Django #Python
Wagtail’s common StreamField blocks are mostly thin, convenient wrappers around Django form fields, adding validation, widgets, formatting, and editor-specific behaviour. By reading Wagtail’s source—or using an editor’s “jump to definition”—you can discover supported options such as `rows`, minimum and maximum values, validators, date formats, rich-text features, and chooser restrictions. The speaker explains how blocks such as `ChoiceBlock`, `RawHTMLBlock`, and the page, image, and document chooser blocks are built through inheritance, arguing that inspecting the source makes StreamFields easier to understand and reduces the need to write code from scratch.
Summarised automatically from the transcript.
Automatically transcribed, so expect mistakes in names and technical terms.
Hello and welcome back to another lesson on learning Wagtail. In the previous video, we figured out some somewhat hidden fields for a char block. And you can actually see it on my screen here where it says required is equal to true help text min length, max length, and template. And we sort of went How do we figure out where these fields are coming from? How do we access these fields? How do we know which ones we can give a stream field? And we learnt about uh jumping to a definition with your editor, or if you don't have that feature, that's totally okay because you can always Reference the Wagtail Repo. Well in this video we are going to do something very, very similar, but we're going to speed it up So if you haven't watched the previous video, you're going to need to watch that one
about how we got to certain areas, certain files, how we even figured out where Char block comes from and what the source code looks like. You're gonna want to watch that previous video. Now to get started I have two uh windows here. Let's see if I can can move that over. Yep. Okay, so I just adjusted my window there On the left I have our project called MySite, and on the right we have fieldblocks. py which comes from Wegtail. Now we can see that we have all sorts of stuff in here. ID for label, render form. This is just a regular field block by the way. But we also have like text block. You can set a min length and a max length. Or block quote block Uh this one takes a value and possibly context.
Float block. This is a good one here. Let's actually let's make this a little wider. Float block We can see some of the fields here, and this is actually getting a little bit interesting because we can see that a self. field is equal to basically forms. whatever the field is with the keyword arguments or the keyword parameters as Well the keyword parameters. But this one is using self dot field. Now if we go back up I believe I saw it up here. Yeah Text block doesn't use that. Text block uses self. field underscore options, whereas the rows aren't part of the field options at all. It's actually just self. rows, and that comes from a keyword argument called rows. Now if you're wondering how to apply that We would change this to a text block
and we would simply put rows is equal to three or thirty, however many you want, something like that. I'm just gonna undo that. Now scrolling back down here we can see we've got a decimal block, a regx block. So really we're just going through all the stream fields and all of these are represented in the documentation at docs. wagtail. io But it is impossible to cover every single thing inside of the documentation just because projects get rather large and you can't always write everything, otherwise you're gonna lose interest from people, and that's totally understandable. And so in this video we are Basically exploring in a URL block. Does it have a min length? Does it have a max length? It comes with validators, that's pretty cool. I think a lot of these come with validators to be totally honest.
Most of them do anyways. A Boolean block, uh yes or no block, it's basically a check mark box. You give it required is equal to true or false, help text is a string. Or none. And self dot field is equal to basically a Django Boolean field where required is equal to required and help text is equal to help text. It's just reassigning some of these things with a few extra niceties on top of it that are being inherited from field block. Date block is one of these ones where it's like self dot field underscore options And it's gonna try to do some work in here. So it's gonna try to pop input formats. And if there are no input formats, it's just going to pass and that's totally okay. And then self. format is taking a format.
So whatever kind of formatting you want to format this block with. And that would be date formatting as well. So we've got a time block in here, a date time block, which is hybrid of both An email block, which is really just a URL block or a text block, but validates against a email field. An integer block, min value, max value, validators. These are just numbers, really. Choice block, this one's pretty interesting. So we've got choices is equal to none. Default is equal to none. Required is equal to true, help text, validators, and additional quargs. But we can see in this one it's actually doing a lot more than all the other ones. So this one that is setting up constructor
keyword arguments. It's checking to see if it's required, it's checking to see if there is help text or not, and it's setting up that constructor for us. And then it's creating a Django choice field. And uh basically it's just gonna pass what it's trying to validate into the choice field. So it creates a proper choice field So you can see on the surface how a stream field can look a little bit complicated at first, but once you really get into it, it's really just a nice way of representing Django fields. Django fields are highly technical. and they don't come with a lot of goodies and you have to write a lot of stuff yourself. Whereas in Wagtail, that's not true at all. Wagtail you can basically say, I want a rich text block. I want to be able to tell it which editor to use.
and I want to give it particular features. So maybe I just want bold, italics, and links. And I don't want anything else. No images, no embeds, nothing like that. You can limit these things. by simply passing in features into a rich text block like we did in the previous video with our charblock over here Now I'm skipping down to the raw HTML block. This one's pretty neat. I really like this one. It's strangely useful in a lot of cases, even though really it's just a decorated char field. So this one comes with required help text, max length, min length, validators, and a widget. And the widget is basically using the text area so you have more than one line of text. And it just wraps all of this together into what's called a raw HTML block.
So jumping down to the chooser block here, we have a chooser block for choosing, well, all sorts of nice things. This is how Wagtail sort of creates its ability to uh choose pages and images and documents. So uh just scroll back up here the chooser block this is really just setting up the page chooser image chooser and document chooser for success It's giving it a bunch of properties and methods that are the same right across the f right across the board and it allows us to Change them if needed. So for instance, that was our chooser block, but down here we have a page chooser block and we can give it a page type, can choose root. target model, and all the other keyword args.
Now these keyword args can also include required and help text and validators because they're all coming from the chooser block. Now if you're wondering, Caleb, how did you figure out it's coming from a chooser block? Well I went down to the page chooser block and it is simply inheriting from the chooser block. So nice and easy. It's going to check to see if there's a target model. If there is a target model. It's going to try to assign that as the page type. It's then going to check to see if there's a page type. If there is a page type, it's going to convert single stringslash model into a list. And if there is no page type, give it an empty list. And so that's basically a list of pages that you can choose with a page chooser. Now we don't see the image chooser block and we don't see the document chooser block because those are actually in their own separate Wagtail modules.
It's still all in that same Wagtail repo, however, it's just not in this particular file. Now if I wanted to jump over there in VS Code I can find my folder that I'm in and I could go from Wagtail. core, go into images, and we can see, oh, there's a bunch of stuff in here as well So we probably want images. Where are you? Blocks, that's what I'm looking for. So we are in Site packages, Wagtail images, blocks. py, we've got our image chooser block, which inherits that chooser block we were just talking about. And a bunch of other stuff in here. So The point behind this video is to not necessarily get you familiar with every single stream field. It's to show you that a lot of stream fields are actually very, very simple.
And I mean even the image chooser block, if we take a look at this, is not very complicated. I mean if we take the time to actually read through this, it's not going to be very hard to understand. And for me and hundreds of other people, that is a massive win for Wagtail, because they've taken something complicated like Django and made it super, super simple. Now again if you ever need to figure out how I got here, if you're like, well, that's cool, Caleb, but I don't know how you actually got this to this particular file. You're gonna have to go and watch that previous video. It's the first stream field deep dive. Really all I did was use the jump to definition, but I also explained in there how you can avoid using jump to definition, maybe you don't have that feature, and just go straight to the
Wagtail repo. And if you go through the Wagtail Repo, it's pretty easy to find this stuff as well. So there's nothing for me to commit in this video, so there's not going to be a commit, unfortunately. We don't need to reference any sort of code or documentation. I will leave the link to the Wagtail docs to this particular field block file in the description down below. And again, just remember. This is not a video where you're supposed to actually get your hands dirty with a lot of code. This is simply conceptual. You're supposed to understand a little bit more and write a little bit less. Now as always, I'm Caleb Tallin. I'm the voice behind the video. Thanks for tuning in today. I hope you learnt something about Streamfields. I hope this video was useful. It was a little bit abstract for me to do this kind of video.
But uh I hope it was still valuable to you. If you did find this video helpful, don't forget you can always subscribe, share, or leave a comment, or better yet, you can always join us on Slack. Go to Wagtail. io slash Slack and you'll be able to sign up for the Wagtail CMS Slack. But if maybe that's not your thing, you can always just binge watch all these videos or reference all the vi all the other videos. by going to wagtail. io slash course and it will bring you to this YouTube playlist where you can see all of the videos. Thanks again for tuning in and I'll see you in the next one.
Use your editor’s “jump to definition” feature to inspect the block’s source code, or browse the corresponding files in the Wagtail repository. The constructor and inherited classes show which keyword arguments are available.
Discussed at 0:00Pass a `rows` keyword argument when creating the block, such as `TextBlock(rows=3)` or another desired number.
Discussed at 2:20It supports options including `required`, `help_text`, `max_length`, `min_length`, `validators`, and a widget. It uses a textarea widget so authors can enter multiline raw HTML.
Discussed at 5:25`PageChooserBlock` inherits from `ChooserBlock` and can accept a target model or page type. A supplied page type is converted into a list of selectable page types; without one, the list is empty.
Discussed at 6:57They are in separate Wagtail modules rather than the general `field_blocks.py` file. The image chooser, for example, is defined in `wagtail.images.blocks` and inherits from `ChooserBlock`.
Discussed at 7:45Note: We understand that names change, people change, and bodies change. We respect each individual's journey and privacy. If you have any concerns about a video or need us to remove content, please don't hesitate to contact us. We will handle your request with care and promptly address any issues.
Published September 19, 2026
Published July 9, 2026
Published May 20, 2026
Published April 16, 2026
Published April 1, 2026
Published March 10, 2026