Video Tour of Wagtail 8.0
Published September 19, 2026
This video is from Wagtail CMS 2023 .
Django shell_plus with IPython is how I learned Wagtail so quickly. It let me explore the entire Wagtail application and trial/error anything I needed to code, and it allowed me to do it quickly.
Django comes with a python shell where you can import your models and test things out. It's not great out of the box, but we can make it better by using shell_plus (installation instructions are inside) and letting IPython take care of interactivity. This is all helpful for learning Wagtail.
This lesson is less about Wagtail CMS and more about the Django Shell and how to upgrade it to be friendlier and more helpful.
Tutorial: https://learnwagtail.com/tutorials/setting-django-shell-shell-plus-and-ipython
Install instructions:
pipenv shell
pip install django-extensions
pip install ipython
INSTALLED_APPS = INSTALLED_APPS + [
# ...
'django_extensions',
]
Then run (inside of your pipenv or docker container):
python3 manage.py shell_plus --ipython
Learn Wagtail from scratch with the official Wagtail for Beginners Course
https://learnwagtail.com/wagtail-for-beginners/
#Wagtail #Django #Python
The speaker shows how to use Django’s interactive shell to inspect and modify a Wagtail application. They install and configure django-extensions, use `shell_plus` to import models automatically, and demonstrate querying Wagtail pages with methods such as `all()`, `first()`, `last()`, `live()`, `public()`, and `filter()`, as well as Python indexing and slicing. They also inspect page attributes and relationships with tools such as `__dict__`, `dir()`, `get_parent()`, and `get_siblings()`, explain that changes require calling `save()`, and add IPython for tab completion and easier exploration. The main argument is that shell_plus with IPython is an effective way to learn and debug Wagtail interactively, because it allows immediate experimentation without repeatedly editing code and refreshing a site.
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 lesson, we're going to learn about the Django Shell. We're going to install Django Shell Plus, and we're going to get some blog posts, first one, last one, live posts, things like that Now if you come from a Django background already, you are probably familiar with the Django shell. However, if you have been following me throughout this Wagtail course. . . And you're not familiar with Django Shell, or you've never used Django Shell Plus, or you're just interested in learning how to use Django Shell Plus, then stick around because we're going to learn how to get this all up and running. So the first thing I want to do is I'm going to open up my terminal here, and I'm just going to show you the Django shell. So we've got pipend shell, that will get me into my environment, and then I can do python3 manage. py
shell And this is my shell, so now I can do interactive Python things. One plus one equals two. Or I can do uh from blog. models import blog detail page. And that gives me blog detail page, so now I can query all of these. Blog detail page dot nope did that wrong. objects. all And it gives me a query set with our two blog posts in it. Now that's pretty cool. And this is a great way to sort of debug and learn as well. However, In my opinion, this is not very nice, and having to import all of your imports manually kinda sucks. That's that's just sort of the truth. So what we're going to do is we're going to install a better version of this. So uh Control
C, Control D. That gets me out of there. And I'm going to install this thing called Django and extensions. So pip install Django extensions. Alright, so that's installed. And now if I go back into my site and go to dev. py, or if you want this in production, you could also put this into your uh your base. py And we're just going to install Django underscore extensions. Let's head on over to our terminal again and let's do python3 manage. py shell plus. Now this one looks a lot nicer. We can see the things have already been imported, and I can immediately do blog
detailpage. objects. all and I'll move that up so you can see this. And that automatically grabs all of my blog detail page. So I didn't have to import that. I get some nice coloring. It's just a little nicer It's not a necessity, but it is just one of those nice things. If you're going to use it a lot, you might as well make it nice kind of thing. Alright, so let's get a little bit of practice with this. The idea behind the Django shell is You can type something like your blog detailpage. objects object. all. And this will give you all of the pages that are a blog detail page object. Now if you're wondering where I got that from, just simply head over to your blogmodels. py and it is our blog detail page. And I'm just saying, get all of these instances, every single one of them, grab that, give it back to me
And now I can loop through these. So if I I can't do that. So let's do uh let's do posts is equal to blog detailpage dot page. The capitalization is important. For post in posts print post dot title And there we go. So just like that, we assigned all of our blog detail pages to a variable called post, and then we looped through those posts, and we got the title of each one. We could do the same thing with the URL or really any other field that comes along with these Wagtail pages. Now what if you wanted the last one? Well the last blog post is really easy, so you could do like last post
is equal to blog detail page dot. I keep making that typo. Page dot objects dot last Last post. And there it is. So we have a blog detail page. That's our last one. Blog post number two is the last one. But we could also go ahead and we could get the first one as well. So if we wanted to do First post, if you're guessing what this would be, and you're guessing that it's going to be dot first. Good guess. The naming convention is just so surprising. So first post. And we can see that first post is blog post number one. So now if we wanted to get all of our live posts, these are pages that are Well they're published in Wagtail.
So it's a Wagtail page and its status is published. We could simply do posts is equal to blog detailpage. objects dot live. And we can see both of our blog posts are live. We've also done one more before where it was just public where we could add dot public instead of dot live. We've seen that. We can also filter. Just a heads up, be a little bit careful with filtering. Filtering will perform a search in your database using the where clause, and that where clause can get really expensive if your database gets really big. But generally it looks something like this. Posts is equal to uh blog detail page dot objects
dot filter and then we could grab A post by the title and let's say the title has to be blog post number one. And so we only have the one. And so this is a list. A page query set, by the way, is basically just a list of objects from Django. So it's it's basically your model, your entire model inside of a list, and each list item is its own object. Now let's slice this up a little bit. So we've got post is equal to blog detailpage. objects. all. Let's grab all of them and let's see what it's giving us. Blog posts 1 and 2. Okay, so let's get the first post is equal to posts. And basically this is just pure Python at this point. This is first post
is equal to posts index of zero, so it's your very first one. And if I type first post, it's going to tell me that I've got a blog detail page. But I can also do some other things in here. So blog post, underscore, underscore, dict. This will give me a dictionary of everything that's available in here. So we can see things like. We can see things like our custom title has unpublished changes, our URL path, that's an important one. First published ad, that's important. We use quite a few of these quite often. So title, draft title, slug, uh da da da live. Is it live? Does it have unpublished changes basically? Is it in draft mode? Last revision created at custom title. We have all sorts of stuff in here. Next we can do first
post underscore underscore dir. And this one basically is just telling us that this class is located at a certain memory instance in here. So we've got some memory allocated to this class. Or to this object rather. Let's do. First postpost dot get so we've got get parent in there. So first post. getparent that will get the parent page. Let's move that up a bit. We can do first post dot get sibling. And actually I think that one is first post. getsiblings. That one is plural. There we go. So sibling posts.
And that includes itself. And basically at any point in time, if we wanted to, we could come into the shell and we could just tinker around. None of this is actually going to do anything to our page unless we grab a class. So let's say first post. We're gonna grab that first post. We're gonna go first post dot title is equal to and this is an example of how we would save something in our shell. So we do first post dot title. is equal to uh first blog post test title just so we can actually see that it's saved. Now this is not saved at this point. This is just changing the property inside of that class. So if we were to ever get rid of this this uh variable, then the title would go back to normal. And what we need to do is run first post. save. And if I run first post
again, we're going to see that that title is now the new one that we made Okay, so there's one more thing we can do with this uh with this shell. So I just got out of my shell and I'm back into my pipenv. If I wanted to do pip install ipython. Mm-hmm. Just wait for that to install. Alright, that's installed. So now I can do Python 3 manage. py shell plus dash dash i Python. And this one in my opinion is actually even nicer. So we have uh we can do a blog post page. So we can get first post is equal to blog detail page dot objects dot first. First post. And as soon as I hit tab, so I hit first
post and then a period and then I hit tab, it autofills for me. So this is even nicer. So that's the iPython extension. And all you have to do is do pip install ipython. And now we can see all of the different methods on you. So add child, add root, add sibling. What is the Ajax template? If there is an Ajax template. Approved schedule, alphabet, blog image. We have all these different things in here. So content, copy, custom title, that one was ours, draft title. Uh, expired, expired at flex page. Oh, this is a property saying is this a flex page or not? This particular one is not. It is a blog detail page. In fact, let's let's look at this one This one says blog detail page has no flex page.
And it's because it's not a flex page. But if we did do do do do do go down here, first page to blog detail page. Uh-huh. It actually comes back with something. This says that basically this is a blog detail page. So if you're ever wondering what instance is my class, like which page type is my class, you can always do that. You can always check by doing dot and then the class name in all lowercase. First post, let's uh let's go backwards this time. So we've got URL, URL path, we can unpublish a page, we can uh make it JSONified. We've got a title, we've got a template, step length, specific class. We're going to talk about specific in a couple of videos. That is a very important one. This is actually that's actually exactly why we're learning this right now. Uh sites rooted here, show and menus.
We've got all sorts of things in here. So we're not going to go through all of these just because there are so many of them. However, I I really do encourage you to open up your Django Shell Plus with iPython and get in here and just take a look at some of these. Maybe tinker around see if it throws an error like uh like when I did first postpost dot flex page and it threw a big old exception there Is Leaf is descended of? Is Navigable? I mean these are all really really good things and most of the time these are named quite explicitly so it's really easy to understand what you're actually working with. So for instance is child of I mean that makes pretty good sense to me is a child of a certain page instance or certain page class type
Uh go live at, that's for publishing. Get tree. We've got all sorts of stuff in here. So yeah, go ahead and explore with this one. This is really, really good for learning your Wagtail. Especially interactively because when it's interactive like this, you can actually go and make immediate changes. You don't have to change something in your code and then restart Django and then load up your browser and hit refresh. You can just do all of this stuff in here. So So this is probably one of the most powerful features that you can use to actually learn Wagtail. Is just get in here, get your hands dirty, don't worry about breaking things, because honestly if you if you break an entire site, well it's on your local host, so you can just start a new SQL. Lite three file, that's totally fine. Or if you're on Postgres or something, you can always create a new database. It's not a big deal
really And then yeah, just go and uh go and explore. Go and try things. Go try to break things. Like if I ran delete right now, this will delete my page. This is my custom title for instance, right? So this is my custom title as you can see. It actually just outputs the custom title for me. That's all there is to this. So in my opinion, I really think everybody who's learning Wagtail, and Django actually, should be using Django Shell Plus along with iPython. It just makes the learning experience so much better and so much faster, and you can just sort of do everything you need inside of this shell, which is really, really fantastic. So again, this is not necessarily a Wagtail lesson, but knowing this is actually really, really helpful to learning Wagtail.
It is one of the key components my success in learning Wagtail was just tinkering around a lot. And in the next few lessons we are actually going to use this a little bit more. And this is actually why I needed to show you this, was because we're going to be learning about this thing called specific eventually. I think it's a couple lessons from now. When we're talking about specific, it's just a lot easier to do it inside of a Django shell instead of inside. of our context inside of our website so that we don't have to save, wait for Django to refresh, go refresh our page. We can just do it all instantly inside of the shell. So thank you for joining me on this little journey about really not learning Wagtail, but the Django Shell in this episode. I hope you learned something valuable. If you did, please hit that subscribe button.
You can share, you can comment. Let me know what you liked about this lesson, and I am the voice behind the video. My name is Caleb Tallinn. If you want other lessons on actually learning Wagtail. You can go to learnwagtail. com. There are tons of tutorials and videos on there already. And if you find anything inside of your Django shell and you want a little more explanation about what it actually does. Don't forget you can always go to docs. wagtail. com or github. com slash wagtail slash wagtail and check out the source code.
Activate the Pipenv environment and run `python3 manage.py shell`. You can then import a Wagtail page model, such as `BlogDetailPage`, and query it with its manager.
Discussed at 0:45Install `django-extensions`, add `django_extensions` to the project’s installed apps, and run `python3 manage.py shell_plus`. Shell Plus automatically imports the available models and provides a more convenient interactive shell.
Discussed at 1:31Use `BlogDetailPage.objects.all()` for every post, `.first()` or `.last()` for the first or last post, and `.live()` for published posts. You can also use `.public()` for publicly accessible pages.
Discussed at 3:52Use the model manager’s `filter()` method, for example `BlogDetailPage.objects.filter(title='Blog post number one')`. This returns a page QuerySet containing the matching objects.
Discussed at 5:23Use IPython’s autocomplete and inspect the available methods and properties, or examine values with attributes such as `__dict__` and methods such as `get_parent()` and `get_siblings()`. Interactive experimentation lets you learn and test Wagtail behavior without repeatedly editing code and refreshing the site.
Discussed at 6:09Assign a new value to a model property, then call the object’s `.save()` method. Changing the property alone only changes the in-memory object; `.save()` persists it to the database.
Discussed at 7:40Install IPython with `pip install ipython`, then run `python3 manage.py shell_plus --ipython`. In the resulting shell, pressing Tab after an object and period provides autocomplete for its methods and properties.
Discussed at 8:25Note: 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