Video Tour of Wagtail 8.0
Published September 19, 2026
This video is from Wagtail CMS 2023 .
When querying for a Wagtail Page that has child (Subclassed) pages, you'll receive all of the pages in your QuerySet. There are times when you simply want the child pages (all types), a specific type of child page, or just the parent page itself with no children. In this lesson we'll explore Wagtails .not_exact_type() and .exact_type() methods.
There are several ways to query your Wagtail Pages and return QuerySets containing only the page classes you want. In this video we'll learn how to:
[ ] Only get Parent Pages (even if Child Pages exist)
[ ] Only get Child Pages from a Parental Query
[ ] How to get Specific class data for Child Pages
QuerySet Wagtail Docs: https://docs.wagtail.io/en/latest/reference/pages/queryset_reference.html
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
Wagtail’s multi-table page models let a parent model such as `BlogDetailPage` return both its own pages and subclassed article or video pages. To retrieve only parent pages, filter a live queryset with `exact_type=BlogDetailPage`; to retrieve only children, use `not_exact_type=BlogDetailPage`. The speaker also shows how `specific(defer=False)` retrieves subclass fields and methods, and explains that mixed child querysets may require type checks or `try`/`except` before accessing fields that exist only on one subclass.
Summarised automatically from the transcript.
Automatically transcribed, so expect mistakes in names and technical terms.
Hello, welcome back to another lesson on learning Wagtail. In this video, we're going to be talking about child and parent page queries. So in the last couple of lessons, we looked at subclassing and how to get specific properties from subclassed classes using dot specific. And dot specific, which is That guy right there. We used that in the template. We did a little try-catch. Uh we broke a couple things. We tried a couple things. We learned how to basically get properties on a child class that don't exist from inside of a query set. Basically the problem that we were solving was if you go and get all of your blog detail pages, but there are child pages like a video blog page and an article blog page.
you aren't able to naturally access all of those properties on the article and and the video blog page They just aren't accessible right away, so we have to use dot specific. Now there's actually another way that we can do this if we go through the Python way of doing things. And in this lesson, I actually want to show you how you can get just child pages and how you can get just parent pages as well. So I'm going to enter my environment here, pip and shell. Python 3 manage. py shell plus iPython shell plus comes from the Django extensions that we installed several lessons ago. iPython, you can install with pip install ipython, and that just gives us a nice Django shell.
So this looks pretty good. This does a lot of importing and magic for us. So for instance, we can do uh blog listing page, autofills for us using tab. I can use dot and it gives me all sorts of things that I'm allowed to do in here. So the first thing I want to show you is how to get specific pages because all we've been doing so far is post is equal to blog detail page dot objects. all and that gets us all of our blog posts. Now that's good, but what if we only wanted blog detail pages, which it thinks all of these are blog detail pages, or what if we just wanted to get article pages or video pages? Now there's a way to split this out. And the main thing you need to know here is that there are different models So for instance, not the blog listing page, we have a blog detail page, this is our parents page, and
underneath it, or as a child page, I'm doing air quotes here, a child page. We have an article blog page which inherits from our blog detail page. This one is our parent. This one is our child. We also have a video blog page. This one is our parent, the blog detail page, and the video blog page is our child. Now how do you get just these pages? There's a couple ways to do this. And it really depends on your scenario here. So the first way to get just, let's say, video pages is you can type videos is equal to video. Videoblog page dot objects dot live that will give you all of the live video pages and if we type this nope If we type this, we can see that there is one video page in our query set, which we could then loop through and we could get all of the YouTube
video IDs. For instance, the YouTube video ID, which only exists on this class. If we wanted to get just the article pages, we could do articles is equal to article blog page. objects. live articles And there we go. We also have one page in here that's an article page. The problem really stems from when we try to get all of our blog pages. So let's say our blog post is equal to a blog Detail page, that's all of them. Objects. Objects. all. And that's basically saying I just want I just want these pages I just want these ones, I don't want the video ones, I don't want the article pages, I just want these regular blog posts.
And if we do this, we're going to see that there's four. Now we know that article blog page and video blog article, we know that these two here are actually not blog detail pages. They inherit from blog detail pages, but they are not themselves blog detail pages One is a video blog page and the other one is an article blog page. So how do we separate these? So let's talk about getting just the parent page. We want to get just detail page. We don't want to get the article blog page and we do not want to get the video blog page. How do we get that? Now this one is going to look a little bit funny, but let's let's type this out and walk through this. So let's do post is equal to blog detail page. dot objects dot live and then we're going to want to specify an exact type
the exact type that this class has to be so In this query set, we know that this is going to return four blog articles in here, four blog posts or four blog objects, if you will. We need to make sure that it is not a video page and it is not an article page. Or, inversely speaking, we want we want to get just blog detail page. So let's say the exact type is going to be the blog detail page And as soon as I hit enter here, we're going to see that there are only two objects inside of our page query set. And there we go. We have our blog detail page. And this one gives us our first blog post and our uh blog post number two. So we know that those are just blog detail pages
That does not include any children. So that is how you get your parent page. Now, if you want to get just your child pages, let's say we wanted to get both article pages and video pages together, but we did not want any blog detail pages, we could do something very, very similar. So we could do post is equal to blog detail page because we want to get all of them. dot live because we only want live pages and then we specify the exact type that we don't want. So let's do uh not N O T exact type. Blog detail page. So what this is saying is basically grab all your blog detail pages.
We know that's going to get all four of these pages. Make sure that they're live. Again, all four of these are published, so they are live. And we're saying it cannot be the exact type of blog detail page. So basically get all the blog detail pages, including the children, and then strip out the parents And there we have it, we have a blog detail page with an article and a video. Now, we are going to run into an issue here because what happens If we loop through these for post and posts, print post dot subtitle Now, if you're wondering where I got subtitle from, I just got that from the article blog page.
This has a property. It is unique to this class called subtitle. This is going to throw me an error. As expected, object has no property attribute, subtitle. Now if you're wondering, well why is that, you might want to go back one video we talked about specific. Uh we're gonna talk about a little bit more, but the prior video will go into it a lot more than this one will. And in fact, let's uh let's get more specific with this. So let's say articles is equal to an article blog page dot objects dot live. And then articles will show us one. This is a query set. This is basically a list of objects, a list of page objects. So we can do for article in articles.
print article dot subtitle and this will work just like that that's expected but the difference is that here we said specifically grab the blog article page whereas if I scroll up here Here we were grabbing the blog detail page. So we again we were still grabbing that parent page and we were stripping out the parent page and left with all the child pages. So how do we get this subtitle when we need to use specific? Well that's a great question. We can do articles is equal to blog detail page dot objects dot live dot not nope let's not do that let's do exact type exact type is equal to
Article blog page. Articles. And so it only returned the one article page, but it still thinks that that class instance is a blog detail page. And that is in itself somewhat problematic And the way we get around this is quite simple. We just append specific. Specific, we put a keyword in there, not refer. It's called defer. is equal to false. By default, defer is equal to true. So that says basically don't get all the additional classes or don't get all the additional properties rather when trying to get this page or this type of page. So what we're going to do here is say defer is equal to false. So basically as soon as you run this, also run one more query to go and get all those additional properties.
And when we do articles, we're going to see that now it is an article blog page. We have specifically said drill down, get that child page, and now we can do a proper loop. So for article in articles. Print article dot subtitle and this will work. Bam! Just like that. That is really, really nice Now there's one more thing we can do because we need to get the child pages. Let's say we want to get all of the child pages. We want to get all the subclass pages from blog detail page. How do we get those? So we can call this one posts is equal to blog detail page. objects dot live because we want all the live ones. Dot not exact type is Going to be a blog detail page.
So again, grab all your blog detail pages, including your child pages, then strip out your parents. Dot specific, and I'm going to show you this one here. This one now, instead of saying it was a blog detail page and a blog detail page, this one is now specific. It says this one is an article blog page And this one is a video blog page. So now we have access to those methods and properties on each of those if we were to loop through these. So we could do four post in posts. print post dot subtitle subtitle and assuming that these come out in the same order that they're printed here one subtitle will show up and Yep, one title one subtitle showed up, and then we get object has no attribute subtitle. Which is expected because the video blog page actually does not have a subtitle method or a
property rather. And because it doesn't have that property, this no, it has no attribute, it's going to error out. So you simply wrap that in a try accept and life will get a little bit easier. Okay, so I'm just gonna clear this off so that we can see what's going on up top. And let's do for post in posts. In fact, let's not do that. Let's see what we're working with. We have posts, so let's do four post in posts. And we want to try to get the subtitle and we want to try to get the YouTube video ID depending on what the post type is. So we can do this a couple different ways. We can say, for example, we can check to see if post dot article blog page. We can also check to see if the post is do to do do do a video blog page.
And in fact, I'm actually gonna jump back one step and even show you how that works because this is really really important too. So we can do let's say post Our first post is equal to posts, the very first one. So this is going to be an article blog page. There it is, we have our article blog page and If we did post. article blog page, we're going to see that it returns itself. And if we did post. We're going to see that it has no video blog page attribute. It just doesn't exist in this class. So what we can do is we can try and accept that now.
Move those back up there. So we've got posts and posts. And what we can do here is for Post and post. So we're gonna loop through all of these that are output on number 35 here. And we can try post is equal to Post dot article blog page. Mm-hmm. Accept exception. Again, I am being lazy with my exceptions. I'm not doing proper exceptions here. These are just Terrible. Terrible ways to teach you how to do exceptions, but for demonstration purposes, I think this is totally fine. And we could pass or we could print the exception. We can do something along those lines. Now assuming that this does not throw an exception, what we can do is we can do
uh da da da let's do print post dot subtitle and this will just print out our subtitle. for the one page. It's going to completely ignore the blog video page. Just like that. So that's how we sort of wrap a try accept. uh inside of a loop that's looping through a query set that has multiple classes. Now if that sounded really complex, I'm gonna break that down for you We have an article blog page, we have a video blog page, and a query set. Essentially, this is just a list. This has a list with two different blog pages in it, two different Wagtail pages that are in it We're going to loop through each one, so get us the article blog page first, and then get us the video blog page second.
And basically what we're saying here is Try to get that article blog page. If this is in fact an article blog page, this will not throw any exception. This will not complain at all. This will actually return itself. And then we could print post dot subtitle because we now have that subtitle. Okay, and then we're going to loop through each post. So we're going to loop through article page and then video page And we are going to say basically post is equal to post dot article blog page. If this does not throw an exception, basically it won't get caught in here We know that we can access post. subtitle. We can also do a try and accept on here. We can try post. subtitle, and if that doesn't throw an exception, then we can keep running forward. There are several different ways to go about this
But essentially, this whole lesson was about how to get just specific pages, how to get just parent pages without any of the children, and how to get just child pages without any of the parents and then how to specifically go and grab the properties that are unique to each class. So that's all there is to really know about uh I guess getting parent pages, child pages, and specific pages If you like this lesson, don't forget you can always check out learnwagtail. com. My name is Caleb Tollin, I'm the voice behind the videos. If this wasn't enough detail for you, you can always check out the docs on docs. wagtail. io. They actually have really, really good documentation. They actually have an entire page. I'll leave the link down in the description below, but they have an entire page just for dealing with different types of query sets.
Now we only went over two different types. We used exact type and not exact type, but there are actually tons of other types, and I really, really suggest going and checking them out because they are super super useful. And hey, if you like this video, if you learned something, don't forget you can subscribe, you can share, you can comment. And for more tutorials, much like this one, you can find them all on learnwagtail. com.
Query the child model directly, such as `VideoBlogPage.objects.live()` or `ArticleBlogPage.objects.live()`. This returns only live pages of that specific subclass and lets you access its unique fields directly.
Discussed at 2:22Filter the live `BlogDetailPage` queryset with `exact_type=BlogDetailPage`. This keeps only pages whose exact model is the parent, excluding article and video subclasses.
Discussed at 4:50Start with the live `BlogDetailPage` queryset and use `not exact_type=BlogDetailPage`. That includes the subclasses while stripping out pages whose exact type is the parent model.
Discussed at 6:21Filter by the child’s exact type and call `.specific(defer=False)` so Wagtail retrieves the child instance and its additional fields. You can then access fields such as an article page’s `subtitle`; for mixed child types, handle fields that do not exist on every subclass.
Discussed at 8:39Note: 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