Headless Wagtail CMS: Serializing RichText Stream Blocks
Published November 29, 2023
This video features Kalob Taulien at Wagtail CMS 2023 .
In the land of Django and Wagtail, sometimes you need custom Django Models but Wagtail doesn't let you edit these models by default. And personally, I don't believe in giving a client 2 admin dashboards to operate in. So let's add a custom Django Model to our Wagtail website using a Wagtail ModelAdmin.
Tutorial: https://learnwagtail.com/tutorials/how-register-django-model-wagtails-modeladmin/
GitHub Commit: https://github.com/CodingForEverybody/learn-wagtail/commit/0026c6f29c0b1e97488bcaa8300cad9780a8d349
Gist: https://gist.github.com/KalobTaulien/8a4450c874f97ac49571495b76365f1b
Learn Wagtail from scratch with the official Wagtail for Beginners Course
https://learnwagtail.com/wagtail-for-beginners/
Used in this video: Wagtail 2.4, Python 3.7, Django 2.1.5 #Wagtail #Django #Python
Kalob Taulien shows how to create a Django `Subscriber` model with required email and full-name fields, run migrations, and expose it in Wagtail’s admin using `ModelAdmin`. He configures the sidebar label and position, list columns, search fields, and singular/plural display names, then enables Wagtail’s model-admin app. The resulting records can be created, searched, edited, and deleted from Wagtail without being pages, snippets, or site settings.
Summarised automatically from the transcript.
Automatically transcribed, so expect mistakes in names and technical terms.
In the last lesson, we ended up adding global site settings to our site so that we could access a Facebook, a Twitter, and a YouTube URL from any template And in this video, we're going to do nothing related to that. In fact, we're actually going to add a new model from Wagtail, and we're going to add it into our Wagtail CMS so that it can be managed in there. Now the idea that I have for this lesson is eventually we're going to have a blog, and when you have a blog, often you want subscribers. So we're going to create a subscribers model. Now if you open up your terminal and I'm already inside of my pip environment, I'm just going to write python3 manage. py
Start app subscribers and then python 3, manage. py run server Everything looks a-okay so I'm gonna open up VS Code again and let's go into base. py and enable our new app. And this one is called subscribers Now I'm gonna close that because we're not gonna need that any longer. Now you can see we have a folder in here called subscribers. We have admin apps models tests And views. We haven't touched tests or views really. We haven't touched admin at all, but we're going to. And we've done pretty much all of our work inside of models. Now the first thing we need to do is we actually need to create a model. So let's go ahead and create a brand new model called subscribers.
So class, we're just gonna call it subscribers. And it's a models. model. And all this is is a subscriber model. And it's gonna hold What do people subscribe with? It's gonna hold their email, it's gonna hold their first name, it's gonna hold their last name. Make that slightly bigger for you. So their email is going to be models dot let's do a chart field just because there are so many different domains out there we might want to cover a lot of different email addresses Required is not the right way to do it. Blank is equal to false. There always has to be an email address. Null is equal to false. There always has to be an email address in the database. And help text is equal to email address.
Next we have our first name is equal to models. Actually, let's not do first name. We don't actually need that. Let's just do full name. Full name is equal to models. Charfield, I actually forgot a max length in here, so max length. What's the longest email address I've ever seen? Probably somewhere around 100 characters. Full name, again, max length. I mean this one really varies depending on culture, but let's say roughly 100. You can go significantly higher if you want to be really cautious about that. Blank is false. Null is false, so this is a mandatory field, and the help text is going to say first and last name And that is our entire model. Now if we wanted to, we could add
the string representation of itself so that we don't get an object back when we're looking at it in the shell or something like that. So let's. Simply return self. full name and that is it. New line, so flake eight will stop complaining. String representation of this object, I guess. Good enough. Now let's open up our terminal again and let's make migrations. So python3 manage. py make migrations Create a new model called subscribers. And then we do Python 3, manage. py, migrate, migrate. And then Python 3, manage. py, run server, just to start things up again.
And so when we take a look at this, we see absolutely nothing. We have pages, we have settings. We don't have our custom subscribers in here. Now, what I would like to do is in this left panel, I want us to have subscribers in there where we can add and we can manage and we can delete subscribers. Basically the same way we do with with any of the pages that we have or images or documents or anything like that. So we're going to open up our subscribers slash admin. py And we can ditch that because we're going to be using the Wagtail admin stuff. So let's do class. Subscriber admin. And this is going to be a model admin. Now this already looks quite familiar to Django, and that's because it is modeled after Django and it uses the Django framework, so
naturally keep it similar. However, we're going to import this from somewhere else, not from Django. It's going to be from Wagtail. Subscriber admin. That's all that's going to be called. Now we have a few different options that we can add in here. Let's add model. Where is this model coming from? It's going to be the subscriber model that's inside of models. py. We have not imported that, so just ignore that for now. We're going to import it in just a moment. Okay, next one we want is a menu label. What do we want to call this? Let's call this subscribers. We could call this anything we want. It doesn't have to be subscriber or subscribers. It could be blog subscribers, email subscribers. people who like our stuff. Call it whatever you like. And then we have a menu icon, and this one is going to be a placeholder.
Namely because it sticks out, but also because I don't want to go and spend time looking up a proper icon. Just because this is a demo video, it doesn't need to be proper. Although, if you ever clone this project down, please change it. Menu order, this is the ordering. Where exactly in our menu do we want this to show up? And that means somewhere in here. Now I'm just gonna throw a random number in there, 290, and see what happened there. Add to settings menu is equal to false, so let's not add this to our settings menu. Exclude from explorer is equal to false, so we'll keep that in our explorer. And let's do a list display. So list display, again, this looks a lot like Django, doesn't it? Now our list
display can only take fields that currently exist, so we have got email and we have full name. So let's do email. And let's do full name. And lastly, let's add some search fields. Search fields, now we're probably not going to be looking for people. Too often, but if we wanted to, we could have a search field for email and a search field for full name. And we're just gonna make sure that Python always recognizes these as tuples by adding another comma in there Now at this point we've created another model. It's a model admin. But we haven't actually registered it. Again, just like in the world of Django, we have to register this. So let's type model admin underscore register. And this is called subscriber admin. And now, if we save this, we're going to get all sorts of errors, model
admin, subscriber, and model admin register. None of those are actually imported, so we're going to have to go and import those now. From Wagtail. contrib. model admin. I love how this is autofilling for me by the way. Options. Import. model admin and model admin register and let's also import our subscribers model so from dot models import subscribers And that's actually supposed to be subscribers. Although if we go back, uh I believe the proper way is to keep it singular and not plural. So it's user, not users. Subscriber, not subscribers, but
I'm not going to be too picky about that at this particular moment. Model admin register says it is still not imported, and that's because it has a capital R in there When I open up my terminal, you can see that there's no errors in here. So things are good. Now let's open up our browser and give this a refresh and see what happens. Look at that, we have subscribers in here now. Now you're going to run into this every single time that you start this up with a new project. Basically says template does not exist, and that's because model admin is not installed by default with Wagtail. And again, that's just to keep Wagtail nice and fast. If it doesn't need to load extra things, why load extra things? So let's go ahead and load that now. So lastly we just need to go into our base.
py and where we have WagtailContrib settings, we add WagtailContrib model admin. Save that. Make sure there's no complaints. Refresh our page. Oh hello. Now you can see that this doesn't have a plural name or a a singular name set yet. We can change that in just a moment. We can add subscriber, that's probably why we should keep class names singular. We can add a subscriber, so we've got an email and we've got a full name. So let's add an email in here. Let's do Caleb at LearnWagtail. com and my name is Caleb Tollen. Look at that. And let's add another person in here. Let's add. Sample person is going to be in the name. So sample
at example. com and full name is sample person. Now let's check out our search. What if we typed in Caleb? We get me. And what if we typed in sample? We get sample. But what if we typed in example. com? We also get example. I'm just going to clear that search out. There we go, we have subscribers. Now let's go ahead and fix this up because that is driving me nuts. And all we do here is we add def nope class meta No QA please. And let's do verbose name is equal to subscribers. And let's also do verbose nameplural is equal to subscribers. And let's subscribers. Let's change that to
subscribers and let's change that to be singular. Make a new line so flake eight stops complaining and let's go back to Firefox or Chrome or whatever browser you like There we go, it says subscribers, search subscribers, things are looking better. So in this lesson what we did was we created a brand new Django model. We then registered it with Wagtails Admin, not Django's admin, but Wagtails Admin We added a verbose name, both plural and singular. We made sure that the search works. We made sure that there is an email and a full name in here. And now when someone submits a form, which you can add a regular Django form to basically any page in Wagtail, when someone submits a form with their email address and their name, you can automatically create a new subscriber object for them.
Now, if you don't come from a Django background, this lesson may have confused you a little bit, and you might just want to take a look at the source code and tinker around with it a little bit. But the idea is that we added a brand new model to our sidebar here. Not a snippet if you're familiar with those. It doesn't have to be a page, so These actually don't come with a preview or anything. So we notice here, save and delete, that's it. So it's not a page, it's not a site setting. It is an object in the database that can be Updated, deleted, created. And that's all there is to it. So thank you for joining me today while we created a Django model and registered it with the Wagtail admin. As always, my name is Caleb Tallin. You can find me at learnwagtail.
com. I'm one of the authors there. If you have more questions about the Wagtail admin. uh and just registering model admins. There are several more options and in fact if you really wanted to dive into it you could go to docs. wagtail. io and you can even add little thumbnails and stuff in here So if there was an image of the person, for example, you could have a little thumbnail in there. And naturally, if you thought this lesson was helpful to any degree, feel free to subscribe. Click that like button or that thumbs up button, maybe leave a comment, tell me what you thought, and I'll see you in the next video
Define a Django model with required email and full-name fields, then run `makemigrations` and `migrate` to create the database table.
Discussed at 1:34Create a `ModelAdmin` class in the app’s `admin.py`, set its model, menu label, icon, ordering, list display, and search fields, then register it with `modeladmin_register`.
Discussed at 3:53Add the model fields you want to search—such as email and full name—to the `search_fields` option on the Wagtail `ModelAdmin`.
Discussed at 6:13Wagtail’s modeladmin package is not installed by default. Add `wagtail.contrib.modeladmin` to `INSTALLED_APPS` in `base.py`, then refresh the admin.
Discussed at 8:37Note: 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