Code that creates content
Published November 19, 2025
This video features Piko Can Fly and Wagtail at Wagtail CMS 2024 .
In this step by step tutorial co-created with Piko Can Fly, you will learn how to create a robust and feature-rich blog application using Wagtail CMS. You'll learn how to add key features for your Wagtail website as well as some options for customizing your code.
📌 Timestamps:
00:00 - Introduction: Building a Feature-Rich Blog with Wagtail
00:16 - Wagtail CMS Admin Demo
02:17 - Set Up: Create Project Directory and Virtual Environment
03:20 - Install Wagtail and Start a New Project
04:05 - Database Setup and First Migration
04:58 - Create Superuser and Launch Admin Site
06:18 - Home Page Customization: Templates and RichText Fields
09:33 - Adding RichText Fields and Migrating Changes
13:53 - Create Blog App and Register Models
15:43 - Define Blog Models: Blog Index and Blog Post
18:43 - Add Image Gallery Model with Captions
19:26 - Set Up One-to-Many Relationship with Model Cluster
22:02 - Inline Panels for Image Gallery in Blog Post Admin
23:54 - Create Author Snippets for Reusable Author Profiles
25:53 - Define Many-to-Many Relationship for Blog Posts and Authors
27:36 - Implement Tagging System Using ClusterTaggableManager
30:55 - Update Database and Add Blog Index Page via Admin
34:13 - Create Blog Templates Following Wagtail Naming Conventions
37:19 - Adding CSS and Static Files for Styling
39:48 - Add Blog Posts with Authors and Galleries via Admin
42:19 - Create and Publish a Blog Post
45:56 - Render Authors and Author Images in Templates
51:33 - Render Image Galleries in Blog Post Template
53:47 - Display Tags and Add Tag Filter Functionality
57:16 - Create Tag Index Page Template and Add Tag Filtering
59:40 - Filter Blog Posts by Tag in Templates
01:04:19 - Add Navigation Links (e.g., Return to Blog Button)
01:05:10 - Filter Blog Posts by Newest First in Blog Index Page
01:08:18 - Create Method for Blog Post Thumbnails
01:14:03 - Enhance Blog Aesthetics with CSS Styling
01:27:26 - Display Revision Dates for Blog Posts
01:28:34 - Add Wagtail’s Search Integration and Rebuild Index
01:30:14 - Implement Search Feature on Blog Index Page
01:32:40 - Add RichText Links and Style Tags as Buttons
01:39:27 - Display Captions for Images in Templates
01:39:59 - We did it! 🎉 Our Blog is Complete!
🔗Important links:
Source Code: https://github.com/PikoCanFly/blog-si...
#Django #WagtailCMS #webdev #python #fullstack
💻 Wagtail is the easiest open-source Python CMS to use:
Install the demo and start building your first site in 10 minutes: https://wagtail.org/get-started/
What will I learn from this video?
You'll learn how to create and customize a basic Wagtail application using fun animal examples. You'll create a blog that has a home page, a blog page, and several individual blog posts so you can learn the basics of creating sites with Wagtail. You'll learn how to use our StreamField feature and how to customize the blocks your content creators can use on your blog.
📹 Related Videos To Watch Next:
â–¶ Quick Video Tour of Wagtail CMS 6.0 https://www.youtube.com/watch?v=_Vg_lPMipcQ
â–¶ The Latest on Wagtail AI https://www.youtube.com/watch?v=4zfs1u4Vy5Y
▶ What’s New in Wagtail CMS 6.0 https://www.youtube.com/watch?v=2AxLFyOFjQo
Wagtail future proofs your CMS system, as it’s open source, continuously updated and built on Python, one of the most popular global programming languages, used widely in machine learning and big data. So you’re always ahead of the curve when it comes to CMS platforms.
Wagtail is the #1 choice for accessibility, is scalable and most importantly, secure.
👉 Get started with a FREE Wagtail CMS TRIAL: https://wagtail.org/get-started/
and see how easy it is to build a website that works for you.
📊 Read why Google, NASA, and the British NHS, are powering their digital estates with Wagtail: https://wagtail.org/about-wagtail/
🎥 More Wagtail Videos: https://www.youtube.com/watch?v=cne2kxemMAQ&list=PLfwZ-fob20cPvSQ_v1hkjto8BAPN21tLJ
📣 Follow us on social:
#WagtailCMS #Django
Wagtail provides a free, open-source CMS for building structured, editable Django sites. The speaker demonstrates setting up a Wagtail project with Python, virtual environments, SQLite, migrations, an admin user, templates, rich-text fields, reusable snippets, image galleries, authors, and tagging. They build a blog with index, post, and tag-index pages, explaining Wagtail page models, StreamField-adjacent rich text usage, template inheritance, content panels, image rendering, accessibility considerations, and filtering posts by URL tags. The transcript ends while they begin creating a second blog post to test the tag functionality.
Summarised automatically from the transcript.
Automatically transcribed, so expect mistakes in names and technical terms.
Today we are going to create a feature-rich blog website using Wacktail CMS. Our website will come with a homepage. Through it we can access our blog. Let's click on the first blog post. So that's our blog post. Do you see this little icon to the side? Let's click on it. As you can see, it allows us to super easily either go to admin. or edit our page or add another page. Let's click on edit this page. Now we are in the admin and we can edit the blog post We can also preview it while editing on different devices. Let's deselect one of the authors and just like that
it disappeared. Now let's look at our intro field and our body field. They are both rich text fields, which means we have the whole power of rich text in our hands. So we can add images. embed videos and have loads and loads of rich text fun. Also we have an image gallery at the bottom of the page because although we can add images using rich text it's nice to have a gallery at the bottom of the page to keep our page layout consistent. We also have a tagging system, which means that our authors can add tags and our users
can use the tags to find more posts they're interested in. We've also added a search functionality. Coding a blog like that is a wonderful adventure and I can't wait to get started on it with you. Before we start, I would like to thank Torchbox, the agency behind Wacktail, for sponsoring this video. Torchbox is a team of over a hundred designers, thinkers and developers working with organizations to make the world a better place. And one of the ways they're making the world better is with Wagtails, since it's completely free, completely open source, and being maintained regularly by a team of passionate developers. Now let's start coding. Let's begin by creating an empty directory for our project to live.
And now let's open it in a code. editor. I'll be using Visual Studio Code but you can use any code editor you like. Now let's talk about prerequisites There's only one prerequisite and it is making sure you have Python 3 installed and that the version is compatible with Wagtail. I'm gonna make sure that I have Python installed on my system and I have a version Above 3. 9. To do this, I'll open terminal and type the command py-version. I have Python 3. 13 installed, which is the latest stable version if you see an error then you might need to install python next up we need to create a virtual environment
so py mvenv Now we need to activate our virtual environment. So Venv slash scripts slash act. Now let's go ahead and install Wacktail with the command pip install whacktail. Alright, so Wacktail is installing. As it installs, I would like to ask you to subscribe for more informative content and if you're enjoying the video please hit the thumbs up button. Okay, now let's go ahead and create the scaffolding for our project. The command is wagtail start and then the name we want to give our project.
How about we call it our site? Okay, a directory called our site was created. Let's cd into it and install the requirements in requirements. txt. So pip install R requirements. txt. Now let's create the database. To do so I'll type pymanage. py migrate. So as you can see here, a database was created for us.
By default, Wacktail creates a an SQLite database for you. And within it it sets up the necessary tables for the Wagtail site. to work. That being said, Wacktail supports all the databases that Django supports, such as Postgres SQL, MariaDB, MySQL. SQL and Oracle. Now that we have our database set up, we can start creating a superuser, which is a user that has admin privileges. The command is py manage. py create super user. Type a username or leave blank to use pico. I'll leave blank and hit enter okay now I'm prompted to type an email address
now I'll type a password okay now I need to confirm the password type it again Oh, my passwords didn't match. I hope they match this time. Yay, they matched. Super user created successfully. Awesome. Let's run server. So pi manage. laptop pie run server okay our server is running let's follow link And here is our site. Yay! Now we can go to slash admin and since we've created a super user we can actually log in. So we've made the username Pico. and I'll type in my super secret
password. Alrighty we're in. So this is our admin and as expected it already has one page. I'll click on it And the page is called home. If we want it to change its name, we can, because there is a title field. We can call it any name we want or just Keep it as it was. Now let's click on live. So it's the landing page that we've seen before. Let's customize it. To do so, we can go to the home directory and we will find the HTML files in the templates directory Let's click on homepage. html. As you can see
there is an include tag here. In Django and Wagtail, include tags are used to include code from other HTML files. In that case, it's including the code inside welcomepage. html. Let's comment it out. And let's refer. The contents are now gone. Now I want to show you how easy it is to access page variables such as the page title. All we gotta do is use curly brackets. In Django, curly brackets are used to output variables. And then we type page and then the name of the field. So in this case
the title field is just called title. So we'll type page. title And then refresh and here's our page title. Alrighty, before we add more functionalities Let's talk about what's going on with our homepage. html file. Why doesn't it contain HTML boilerplate? The reason is our homepage. html extends another HTML file called base. html that acts as a foundational template It is found in the directory our site under the directory templates. As you can see, it contains the boilerplate. It also
contains the definitions for blocks. Blocks serve as placeholders And we can override them. For example, over here, block extra CSS was used to link to the style sheet welcomepage. css, which is In the static directory, this one. If we didn't want to add extra CSS, we could just remove the entire block. And block content, as you might have guessed is where we write what we would usually write between the body tags in an HTML document. Alrighty, so like we said, right now our homepage only has A title field. Let's
add a body field also. To do this, we're going to go to models. py. As you can see in models. py, class homepage is defined. To add a new field, all we gotta do is decide on the name of a field. For the body field we could just call it body. After we have a name We need to decide what kind of field we want. Wagtail has awesome rich text field. To use it we need to import it. So from Wagtail dot fields import rich text field and now let's set body to rich text field and set blank to true. Setting blank to true would allow us to leave the field empty. A field represents
a column in our database. So by adding the body field we are essentially adding a new column to our home page table in the database. Which means we need to update our database. To do this we first need to make migrations So let's stop the server and to make migrations we just type in the command py manage. py make migration migrations. Let's hit enter and with this a new file was created in the migrations directory. And if we look at it We will find a list of operations. In order for those operations to get applied, we just type the command pymanage.
py migrate Hit enter and right now our database is getting updated. Migrations are over and we have successfully added the body feel to our home page. table. Now let's run server again. So pi manage. py run server. Alrighty, so let's go back to our home page and refresh. Since we have not added the body field to content panels. We will not see it on the admin yet. To add it to content panels, all we gotta do is go back to models. py And we're just gonna need to override the content panels attribute and add the body field to
the content panels list as a field panel. So let's import field panel from Wagtail. ROM Wagtail dot admin dot panels import field Field panel and then field panel body. And now if we refresh, we should see the body field. Let's try. There it is. Let's type something. Maybe you can type welcome to our awesome site. And since this is rich text, we can for example make awesome bold and maybe make welcome italic. And we can of course do more
things. Let's publish. And now if we click on view live, we only see home because we need to add the body field to our template if we wanted to see it. So let's go to our homepage template and let's add page dot body. Now since body is a rich text field, we need to add the rich text flag for it to show properly And in order for the rich text flag to work, we're gonna need to load whack tail core tags. Now if we refresh
we should see our body. There it is! Awesome. Actually let's remove the page title from here because Doesn't make sense anymore. Refresh. It's gone. Now how about we change the font to a sensor font? To change the font for the whole website, we can go to the our site directory To static directory, CSS, and we'll find a file called our site. css. This CSS file is meant for styles you wanna apply on all your templates. So Let's write a rule for the body element. Let's make font family. Ariel, Helvetica, Sans Seraph. And let's hard refresh.
Control F5. Yay, it worked. I think we're now ready to create a blog. So let's stop server. And to keep our project organized Let's create a separate app for the block. The command for creating a new app is pymanage. py. Start app and then the name we want to give the app. Let's call it block. Alrighty. A new directory called blog appeared and that's where the code for our blog pages. is going to live. But before we start writing code for it, we must register it. Let's go to our site directory. Head into the settings directory and then into base.
py. Base. py has the settings for our project. Let's go to installed apps and we want to add blog to installed apps. Just gonna Write blog between Cotation marks like so, add a comma, and that's it. Our blog is going to contain an index page that's going to list The blog posts will create a thumbnail for each blog post with a title, an image, and an intro. We'll also create a blog detail. Page that's going to contain block title, author, date, and of course the post
itself which will have an intro and a body as well as an image gallery. We also want to make it so that we can add tags and if a user clicks on a tag they would get redirected to a tag index page that lists all the posts that contain the tag that the user clicked on Clicked on. Alrighty, so let's start defining our blog pages. So let's go to our blog. app and go to models. py. The first thing we need to do is import Wacktails page model. It's already imp imported in the models. py in the home app. So I'm just gonna open it to the right and just copy the import
statement. And like we've said, we want to define blog index page. So class blog index page and of course it's gonna inherit from Wagtails page model. And how about we give it a description field and let's set it to rich text. To use rich text we need to import it from Wagtail dot fields. Import rich text field. Okay, now let's set description to rich text field and let's set blank to true. And of course we would like to be able to edit the description
from Wacktails admin. To do this, let's override content panels and add description as a field panel. So we're gonna need to import field panel so from wagtail dot admin dot panels import field panel now that we've imported Imported field panel, we can use it and pass an description. Alrighty, now let's define class blog post. Page, which will also inherit from Whacktails. Page model. Let's add a date field So Wacktail allows us to use all of Django
's models fields, including the date field. So we'll setting our date field. to models. date field and we can give it verbose name post date. Verbose name will appear in the admin. As we'll see in a bit. How about we make life easier for our editors by setting default to today's date? In order to do this, we are going to need to import date from date time So from date time import date and now we can set default to date. today. Next up, let's add an intro field. Let's add it to rich text field and set blank to true in case we want to leave it empty.
Let's also add a body field. And let's also set it to rich text and set blank to true. Okay, so we said that we want our block page to have an image gallery. So let's define class block page image Gallery. Having a separate model for image gallery comes with many advantages. One of them is allowing us to easily organize our layout and also reuse our images easily, for example, when we create the thumbnail for our blog posts in the index page. Besides, Wacktail has an awesome model called orderable, let's import it, which will allow us to
sort our images super easily as we're going to see So let's subclass it. We want our blog page image gallery to have a one too many. relationship with our blog post page model and we would like to be able to edit and add images from the blog post page on the admin. So uh let's create a parental key relationship between the blog post page model and the block page image gallery model. To do this we need to first import parental key. So from model cluster dot model
import parental key. Now let's create a relational field and call it page and That's where we're going to establish the parental key relationship between our blog page model. I'll copy its name and paste it here. And our block page image gallery model. Let's set related name to image Gallery. Alrighty, now we want to make sure that if a blog post gets deleted, the images associated with it would get deleted too So let's add undelete and set it to models
dot cascade Now, since the whole point of creating the block page image gallery model is to be able to add images, let's create an image field. Wacktail comes with a super amazing images app called Wacktail Images. It allows us to upload images use them and reuse them. In order to take advantage of it, we need to establish a foreign key relationship between our model and Wacktails. Image model, which is part of the Wacktail Images app. So WacktailImages. image. Now in order to make sure that there is no reverse relationship Between our model and the image model, let's set related
name to a plus. And to make sure that there are no orphaned records, let's set on delete models dot cascade. Now let's add a caption field. So we have the ability to give our images captions. And let's set it to a character field. So models. char field. Let's set max length to 255 and blank to True. So we are going to want to be able to add images for each blog post from the admin interface of that blog post. So let's make sure we create field panels for our image and caption. So let's overwrite panels
and set it to a list with Field panel image and field panel Caption. And now in order to be able to add the images and the captions from the blog post page admin, let's import inline handle and let's override content. panels like we've done before so page dot content panels plus this time we wanna add the panels that we have just defined so in line panel and we're going to reference the related name of the parental key.
So image gallery and to make the user experience of the admin front layer let's add a label and Let's set it to gallery images. Of course we also want to be able to add date and intro and body to our blog post. So let's also add them to content panels. as field panels. So field panel date and field panel intro and Field panel body. Alrighty, next up let's create a model
for our authors. It would be good user experience If we would make it so that we could just add an author one time along with their profile picture and just select the correct author. From the blog post admin page. So let's create class author, which is gonna subclass Django 's model. And let's add the field's name and set it to a character field and set max length to let's say 255 and let's add an image field maybe you could call it author Image and set it to have a foreign key relationship with Wacktails image model just like we've done earlier for our blog page image gallery image field. I'm just gonna copy this line of code and paste it.
And just like we've done for our block page image gallery. We will also overwrite panels in order to add name and author image as editable panels to our admin. So let's set panels to a list with Field panel name and field panel author image. And now in order to turn this model into a snippet Which is a very clever solution to add reusable content through the admin interface. All we gotta do is register it as a snippet. And to do this, we just import register snippet from Wagtail dot snippet. snippets dot models
import register snippet alrighty and now to register it we just use the decorator register snippet like so. Almost done. But in order to make sure that our model has a human readable representation that makes sense, let's define a string method and let's have it return. Self. name. Alrighty, and now we want to establish a many-to-many relationship between our author model and our blog post page model. So in our blog post page model let's add an authors field and we want to set it to parental many to many fields so let's import it. Okay now let's set authors to parental many to
many field. And the class we want to have a relationship with is the author class, which belongs To the blog app that we are coding in right now. So to reference it, we'll write the name of the app and the class name. which is author. And to make it possible for our editors to save posts without inputting an author, we can set blank to true. Now let's add authors to our content panels. So field panel Authors. So since we'll be creating author instances through Wacktail snippets and we possibly have many authors to select from, let's
Make it so our editors can select multiple authors with check boxes To do this, let's override widget and we want to set it to Django's Forms Checkbox Select multiple. So I'm gonna import Django's Forms. So from Django import Forms. And I'm gonna set widget to forms. checkbox select multiple. We've said earlier that we would also like to add tags To each post and make it so that if a user clicks on a tag, they get redirected to a tag index page that lists posts
with the same tag. Alrighty so for this to work all we gotta do is define two more models. The first of which is gonna be the page that the user gets redirected to when they click on a tag. Let's call it tag. index page and it will inherit from Wacktails page model. We're going to be adding logic to it soon. Wagtail provides tagging capabilities through the combination of Django Tag It and Django model Cluster. Django Tagit is a reusable Django application designed to make adding tags to projects easy and fun. We are going to utilize its Tagged item base model in order to
create a many-to-many relationship between our blog post page model And the tag model that was included through the tag it app, which by the way, if we go to base. py and look at installed apps, we would find that both tag it and model cluster are already included for us, which means we are ready to use them. So let's go ahead and import Tag it's tagged item base. I'm just gonna copy the import statements from the docs and paste it. And now let's define class blog post tag that subclasses tagged item base and we are going to
override Content object to set a parental key relationship between our blog post page model and tag its tag model. Now let's set related name we can make it tagged items and to avoid having orphaned records let's set on delete to models dot cascade And since we would like to manage the tags through our blog post page as a single field, we are gonna use cluster taggable manager accessor. I'm gonna copy the import. statement from the docs and paste it
and then go to my blog post page model and add tags field and set it to cluster taggable manager and add the block post Tag model as the through model and then set blank to true in case editors don't want to add any tags. Finally, let's add tags to content panels. I'll just add a comma and add it the same way that we've added the other fields as a field panel Alrighty, so right now we have defined one, two, three,
four, five. Six models. Alrighty, so I think now is a good time to update our database. First we need to make migrations. The command is pi manage. py make Migrations. Righty, let's hit enter. Okay, looks like we've successfully made migrations. And if we go to the migrations directory We should see our migrations file. And if we look at the list of operations, we will find instructions to create the models that we have defined in models. py. with the fields that we have defined for them.
So let's go ahead and migrate. So pi manage. py migrate Great. Now let's hit enter. Yay, we did it! Migrations were applied. Which means our database was updated. Now let's run server with the command pymanage. py. Run server, hit enter. Alrighty. Let's follow link and let's go to admin. Log in. Alrighty. Now let's click on home and let's try to add a child page And check it out!
Let me zoom in so you can see more clearly. Alright, so we have the blog index page that we've defined, the blog post page. And the tag index page. Okay, so let's click on blog index page so we can add a blog index. Let me Zoom out again. Okay, so this is how it looks like. We have a page title and a description. Page title comes included with a page model when you override it. And we have defined description when we created our blog index page model and we did add it to our content panels as a field panel Alrighty, so
let's make the page title our blog. But I'd like to write a description. I recently read a quote. by an unknown writer that went something like this. A blog is merely a tool that allows you to do anything from changing the world to sharing your shopping list. Now if we try to publish and click View Live, we'll find an error that says template does not exist because we have not created a template yet. So let's go back and create a template. So like we've said earlier, templates are HTML files.
And Wagtail looks for HTML files inside templates directory. There is a templates directory in our home app, and there's also a templates directory in the our site directory. And both of them have HTML files. Now let's create a templates directory inside our blog app and let's create inside it another directory called blog. When we use the page model Wagtail handles mapping to templates for us. However, we need to make sure to follow the correct format, which is app label. In our case it's blog, that's why we have created the blog directory inside the templates
directory. And then model name in snake case. followed by. html. Alrighty, so since we're creating the template for blog index page, we are going to name our template. blog underscore index underscore page dot html so now let's stop server and run it again and see if Wacktail will find our template. Okay, so now our server is running. Let's go back and refresh. Alrighty, it found it. There is no longer there. Cool. Alrighty, so like we said earlier when we were
working on the home page template Base. html file contains HTML boilerplate as well as definitions for blocks and other code that we would like to have in all our page templates. So it's important to remember to extend it. And to extend it, all we gotta do is type in early brackets and then percentage signs in between them. Just write the word extends. And between quotation marks, the template we want to extend, which is base. html. And we said earlier that we should write the code that we would usually write between the body field in an HTML file within
block content. So let's write block content and when you open a block you should always remember to close it with and block. And within our block content we probably want to see what we have written in the description field to access page variables or page fields we use two curly brackets like so and then type page. the name of the field we would like to show which is description. And since our description field is a rich text field. We would need to add the rich text filter which is provided by Wagtail through Wagtail core tags which is why we need to
load. Wagtail core tags for the rich text filter to work. Okay, now let's refresh. Yay! Here is our description. Alrighty, we would like to add styling to our blog index page. To do this, we need to remember to import the static Tag and Wagtail, as well as Django, of course, looks for CSS files in a directory called static so we should create a static directory and in it we can create a new folder called CSS and inside it let's create our CSS file we can call it blog index page
dot css alrighty and now to link to it we can override block extracss We should always remember to add end block when we open a block. And inside block extra CSS we can link to our style sheet. So link, rel, style, sheet, type, text, CSS, HRF, static And over here between the quotations, we will type the path to our CSS file within the static directory. So CSS slash blog underscore index. underscore page dot css. Alrighty now that we have linked to our style
sheet let's add a div element which will serve as a container and give it class container and now let's go to our style sheet let's open it to the side let's add styling to container maybe max width 800 pixels and end margin auto. Alrighty now let's hard refresh. So control F5. Oh cool. Now it's centered. Okay, we could also add the page title here. Do this. So we'll just type page. title. Could add it as an h1 element. Okay, now Let's refresh.
Here it is, our blog. Have you guys noticed this little cute birdie here? Let me zoom in. This bird is showing to us because we are currently logged in. Wagtail admin. It is here to make our lives easier. Let's click on it. As you can see, we can click on go to Wacktail Admin, which takes us to Wacktail Admin. We could also edit the page we're on right now or we could add a child page to the page we're on So, since the page we were on is the blog index page, it would make sense to add a blog post as a child. Let's click On blog post page to add one. I'm gonna zoom out. As you can see, all the fields we have added are there.
There's the authors here, but it's empty because we haven't added any authors yet To add authors, we would click on snippets, and that's because we have registered our author model as a snippet earlier, so that's why we see it in snippets. Okay, so let's click on authors. And it says here there are no authors to display. Why not add one? Let's add an author. Let's make the author name Pico. And we can add an author image. So let's choose an image. I'll click on upload, choose file, and how about this intelligent looking capybara? I'll click open and as you can see a title was already filled with the name of the image So by default, Wagtail uses the title as
alt text and alt text is important for screen readers. So maybe we can put a descriptive title and maybe write intelligent capybara. We could also add a disc description and tags in order to help make our images more organized once we have more of them. I'm gonna add some tags like Capybara, Cube, and Animal Alrighty, let's click upload and now let's save. We have created our first author. So now if we go to our our blog page and try to add a blog post page again
We will find Pico is an author and we can tick it. If we had another author, for example, Gombol, let's add an author named Gombol and choose an image Let's upload a new image for Gumball. This is Gumball. Alrighty, let's adjust the title and add a tag. Gumball. And upload. Alrighty, let's save Gumball as an author. And now let's go back to the new blog post page that we were working on and refresh. And gonvol is there is an author that we can select. Alrighty, so how about we create a blog post? So I have prepared a blog post about hippos.
I'm just gonna copy the title and paste it. I'll do the same for the intro. Copy, paste and for the body as well. Copy it. and paste it. And now let's add some gallery images. Okay, choose an image, upload. Choose file. Let's choose this file. Let's call it Hippo in Water and let's add some tags. And click upload. Right, our hippo and water image was added. We can add a caption if we wanted to. We can say Hippos like water, for example.
Right now we can add another image, upload this baby hippo, which makes my heart melt. Let's make the title little baby hippo and add tags again. Right, let's click upload, add one more. How about a second baby hippo? Alrighty, let's upload it and maybe add a caption. Now let's add tags to the blog post itself. Such as hippo, hippopotamus, wildlife, nature animal and let
's hit publish. Okay so now we've published our first blog post but we haven't Created a template for blog posts yet. So let's see what would happen if we click on View Live. As expected, we got a template does not exist error. So let's make the blog post template exist. Let's go back and inside templates blog directory. Let's add a file and call it blog underscore post underscore page dot html which is the name of our blog post page model. Button
snake case. Alrighty, so let's start adding content to our blog post page. html. Okay, so the first thing we need to do is extend base. html and then we want to load static because we will be adding styling. And we also wanna load Wagtail Core tags. And we will be overriding block content in order to add content to our template. Okay, so let's begin by creating a div element that's going to serve as a container
for our blog post. Let's give it the class blog post container and inside it let's create an h1 element where we want to see the title of our blog post. So page dot title. Alrighty now let's Refresh. Yay, it shows. Alrighty, next up we want to show the authors that have written our post. So since we might have more than one author or no authors at all, we're first going to check if an author exists and then we are going to loop through the authors to show all the authors.
So let's use Django 's with tag to create variable authors and set it to page dot authors dot all alrighty when we use a with tag it's important to make sure to add and with now let's check if authors with Django 's if tags so if authors let's also add and If alrighty, so if authors, then we want to create a div element to hold the author information I'll give it class author info. And before we list the authors, maybe we could
write written by. And now let's create an unordered list. And that's where we're going to loop through our authors. So for author in authors. Let's add and For and let's create a list item and give it the class Author item, and firstly we want to show the author image and then the author name We are going to use Wacktails Image
Tag in order to easily render the image But for it to work, we're gonna need to load Wagtail Images tags. Alrighty, now back to our image tag. Since the field that contains the image is called author image Then to render it we're just gonna write author dot author underscore image after that we will specify the size. Let's make it Sixty pixels times sixty pixels. All righty, now let's add the author name in a span element and we've called the field that contains the author name
name so to show it we'll just type author dot name between curly brackets alrighty now let's go back to our page and refresh Yay! Here is our author. Alrighty, next up we want to show the post date. So let's create a paragraph element and give it the class fate. And then we can write published on and show the date using curly brackets in page dot Date. Alrighty, so let's refresh. Yay, the date shows.
Alrighty, now let's create another Div element where we want to show the intro. So let's give it the class intro and Our intro field is a rich text field, so to show it we'll use the curly brackets and then write page. intro and we'll add the rich text filter, let's refresh. Yay, here's our intro. Okay, now let 's create another div element where we're gonna keep our body field. So class body and to show the body field
which is also a rich text we'll write page. body and let's add the rich text filter and refresh Yay, here it is. Alrighty, so I think I would like to edit it up a bit. So I'll click on the little bird and click on edit this page. And I wanna adjust the subtitles by removing those stores and making the subtitles headings Alrighty, now let's publish and view live Right, and that's how they look now. I think they look much better. If we look here, the whacktail bird has a message for us.
It says that There is incorrect heading hierarchy and we should avoid skipping headers. Skipping headers is bad for accessibility, and we skipped headers by going from an H1 to an H3. So let's go back and remove this H3 element and let's make it a paragraph element instead And add a strong tag. Alright, let's refresh. Okay, I think it looks fine. Alrighty, so like we said earlier, we want to show the images at the bottom of the page. So our blog page image gallery model has
a parental key relationship with our blog post page model and the related name is image. gallery. So let's define a variable for the images with the width tag in our template. So I'll call it images and set it to page. DA the related name which is image gallery dot all and we should always make sure to end with next up we want to check if there are any images added so if images of course we need to remember to add and if if images we want to show them so I'll create a div
element to keep our images I'll Give it the class gallery. And now we want to loop through the image gallery. So for image in. images. Of course we should always remember to add and for. Alrighty, let's create a div to hold each image and its caption. We can give it the class gallery. item and we're gonna use the image tag to render our image image dot image It's image. image because the name of the field in block page image gallery model is image.
Alrighty now let's Add the size we want the images to be, let's make it 340 times 340 pixels for now. Next up we wanna show the image caption. So I'll create the a paragraph element and we'll use the curly brackets and write page dot caption now let's refresh okay here are our images nice next up let's add the text let's hear use Django's width to define a tags variable and let's set it to page dot tags dot all and let's not forget to add end with
then we want to check if there are tags so if tags Let's add and if okay, so if tags we want to keep them in a div element, so let's create a div element and give it the class tags and now we want to loop through the tags so for tag in tags Let's add and four and we wanna show each tag in an anchor element.
So Let's just pass it in like so. And maybe you can give the anchor element the class tag button. Now let's go back and refresh. Alrighty, here are our tags. Let's add h -re-f and we are going to set it to slug URL. Tags. So slug URL takes a page slug from the promote tag as an argument. We are going to create a tags page soon and we are going to set it's slug to tags. So right now this is not gonna work, but soon
it will. Now we also wanna pass the tag as a parem so we'll add a question mark and write tag and pass in the tag as a param like so. By passing the tag as a param we're gonna be able to retrieve it and create a method. to show pages that have the same tag. So for now let's go back and refresh. So like we said when we click on a tag We are going to get an error because we have not created a text page yet. So let's go back and let's go to admin. And we want to create our tag index page on the same level as
our block index page. So it's going to be a child of home page. So let's click on Add Child page and let's select tag index page and We haven't added any fields to our tag index page, so that's why all we have is a title field. Let's make it tags and let's go to promote and make sure that slug says tags just like in our URL. Alrighty, now let's Hit publish and let's go back
To our blog page and let's click on attack. Alrighty, we got a different error. This error says template does not exist. Which is true. We haven't yet created the tag index page HTML. Let's create it. I'm gonna copy this, which is the HTML file that Wagtail expects to find. And I'm just gonna paste it in the templates block directory while creating a new file just like this Okie dokie. And now if we refresh, we should see an empty page and we do. So now let's add a method to our tag index page that would allow us to obtain the past
in tag that we pass in through the URL. This one. So def get context self and we want to make sure to pass request also as a param. And now we want to get a hold of the tag that we pass through through the URL. So let's set tag to request dot get in all caps dot get tag and now we're gonna use tag to filter blog posts based on tag so Blog
post page dot objects dot filter and you wanna filter by text name and only get the posts where tag 's name matches the tag. Alrighty and now we want to be able to pass the filtered blog posts to our template. So let's get a hold of the context dictionary so super dot gap context request and we want to create a key value pair with the key being blog posts
And we want to set it to the filtered block posts. So block posts and now Let's return context. Alrighty, now let's go back to tag index page template and let's start adding subcode. First thing, let's extend base dot HTML then let's load static because we'll be adding CSS later and Wagtail core tags Now let's override block content and let's not forget to add end block. Now the first thing we want to do is
check if a tag was passed through the URL. So if request dot get dot tag let's not forget to add and if then we would like to Tell the user that the posts below were filtered according to a tag and it'll tell them what tag that is. So below are posts tagged request dot get dot tag between curly brackets which should show the past in tag so let's go back and refresh Yay, it worked.
Alrighty, now let's list our blog posts. So we'll just loop through them. So for post in blog posts and since we've used the four tag let's make sure to add and for. Alrighty, let's create a div element and give it the class blog post item And let's create a paragraph element inside it. And then let's add an anchor element and have it show the post title so post
dot title and let's set HREF to page URL post. The page URL template tag allows us to super easily retrieve a page's URL. So let's refresh and see if it worked. Alrighty, let's click. Okay, so we got properly redirected to the blog post. I think we would be better able to test the tags if we had more blog posts, right? So let's go to Acttail Admin and Let's add another
child page to our blog. Let's make it a blog post page And I'm just gonna copy from a document I have created earlier So I added a title. I'm going to select both Pico and Gumball as the authors. And now let's copy and paste the intro. And then the body text. Righty. And now let's add gallery images. I'll add this one first. Let me get Capibara face
and let's add uh the tags wildlife animal capybara nature okay Okay, let's upload and let's add another image Alrighty, and now let's add tags to the post itself, like wildlife, nature Capibara Animal And now let's publish Okay, let's view live.
Right, here is our post. Right, let's click on the tag wildlife and yay Both articles are there. Now let's click on the tag Capibara and only the article about Capibara 's is there. Cool! Alrighty, let's go back to the blog post. And how about we add a link here that would link back to our blog? Doing so is very, very easy. Let's go back to blog post page and we want to add the link under the images and above the tags so I'm just gonna create an anchor element and have it say return to blog and I'll set HREF to
curly brackets And then page dot get parent. url and that should do it. So let's refresh And here is the anchor element. Let's click on it and it worked. That's our blog page. So next up we want to list the blog posts on the blog page. And we want to make sure that we get the pages that are Live meaning that are published and not drafts and we also want to list them from newest first So let's go back to models. py
and just like we've done for our tag index page, we are going to override the getContext method to customize the context dictionary passed to our template. So let's add it. So defget context and it takes self and request as params. Okay, and now let's set context to super dot get context request. Now let's create blog posts variable and since our blog post
pages are children of our blog index page so we can get them with self dot getch children And like we said, we only want published articles to show. So we'll add dot live. And we said also that we want to show newer pages first so we can add order By and a negative sign to reverse the order of first published Alrighty, now let's add blog posts to our context dictionary and now let's return
context Alrighty, so with this we'll be able to access the filtered blog posts from our blog index page template. So let's Go to it again and let's add a for loop under the page description. So for post in blog posts let's add and for and let's have each blog post in its own dev So let's give it the class blog
post and let's create an anchor element and have the post title show in it and set Href to Page URL post. Alrighty now let's refresh. It worked. Yay! Alrighty, we have said that we want to also show an image related to each post as well as the intro. But each of our blog posts have multiple images. So how about we define a method that would make our life easier by taking the first image in the gallery and making it the main image?
So let's go back to our models. py and in blog post page let's start defining Main image method and let's define variable thumbnail image and set it to self dot image gallery dot first. Now let's check If thumbnail image exists, if it does, then we want to return thumbnail image dot image else We want to return
none. Now let's go to our blog index page template. Alrighty, now let's use Jane goes with tag to set thumbnail image to post. specific. main image. And of course let's add and with. Now let's check if thumbnail image exists. If it does then of course we want to render it so let's create a div element to hold it. Give it the class thumb nail
image and we want to use Wagtails image tag to render the image which means we are gonna need to load wagtail image tags. Actually let me put static as the first one loaded and now we can load Dwagtail image tags. Awesome. Okay, so the image we want to render is the thumbnail image and let's set the size to three hundred times two hundred pig pixels for example. Alrighty and now let's go back and refresh.
Okay, looks like I made a typo in the models. py I wrote Furt instead of first. Okay, now let's refresh. Yay, it worked So like we've said earlier, we also want to show posts intro. So let's go ahead and Do that. So first of all, let's create another div element to hold both our thumbnail and our blog intro. So let's give it the class. post info and now under our thumbnail let's add another div
element that's going to hold our introduction. Let's give it the class post info and we'll use the double brackets and then post dot specific dot intro and since our intro field was a rich text field let's add the rich text flag and now let's refresh And here it is. So before we begin beautifying our blog, let's add one more post So let's click on Add Child page and we wanna add a blog post page.
This post is gonna be about wagtails, and the title is gonna be this Discovering the delightful world of Whack Tails. Okay, let's select the authors Pico and Gumball. And now let's Add the intro. Alrighty. And now let's add the body. Okay. And then let's add gallery images. And let's add tags. So wildlife, bird, nature. Before we hit publish, let's click on this phone icon
which would allow us to preview our post and see how it would look like if it were published It allows us to preview it on a phone or a tablet or desktop. So Uh this is how our post would look on a phone. I think it looks kinda nice. We're still gonna add styling of course Previewing allowed me to see that there are many things I should fix before publishing. So I'm just gonna go ahead and do that. The cool thing is I can see the edits in real time Righty, looking good. So let's go ahead and publish. Yay! And now if we view live, here is our post.
Okay, let's return to blog. Okay, we said that we want to beautify our blog a bit, right? So let's add some CSS to our blog index page. css So let's open it. And to make our lives easier, we have earlier tried to add classes to our elements to To make styling faster. However, there are still some things that I feel like the styling of our page would benefit from adding, for example. We could have our Blog post title B inside an H two element and we could saw anchors
text decoration to none and change the color to a grayish color Yeah, better. Actually, how about we apply this styling for anchor elements to our entire site So let's just cut it and paste it in the CSS file inside our site directory, the one that's called our site. CSS. Okay, and with this the styling of our anchor elements should change everywhere if we hard refresh. So let's try, let's click on discovering the delight of Wagtail and scroll down
because there are anchor elements here. Oh yeah, there it is. Now let's add an unhover effect. So anchor hover, let's make it text decoration underline Let's refresh. Oh, it works. Cool. Alrighty, now let's go back to our blog index. css and let's give our container div display flex and flex direction column righty and let's set a gap to for example 30 pixels. Okay, and now
let's add styling to the blog post div and maybe start with adding a background color. Oh let's have it be something kind of grayish. Oh too dark Alright, maybe something like this, yeah. Okay, and now let's add padding on maybe 15 pixels Cool and let's make the border rounded a bit. So let's set border radius to 8 pixels, for example. Yeah, much better. Alrighty, and now for
post info, let's add display flex and align items Flex start. Okay, let's refresh. Yay, cool, but we need a gap, so let's add gap 20 pixels and refresh. Okay, I think looks kinda good, right? Right, let's um let's maximize Yeah, looks cool. Maybe we could give our container some extra padding. Padding. Let's say do I need pixels? Refresh. Yeah, better.
However, let's improve this area. Um, so that's Where we have the block title. So block title. We can make its color grayish also. And can add Text align center the font size a bit bigger. So maybe can make it 2. 5 rem for the description let's put it inside a div element give it class Description and
let's make font size Let's say 1. 2 RAM okay nice and now let's make the color let's say something also grayish but slightly different Yeah, like so. I think this looks more harmonious. We can make text align center. Yeah, yeah, that looks better. And maybe could add some padding bottom make it five pixels Or maybe fifteen pixels. Yeah, yeah, better
I like it. Alrighty, next up let's add some styling to our blog posts. So let's go to blog postpage. html. Close this. And we haven't linked a style sheet yet, so let's do that. Let's add block. extra CSS and we should never forget end block and let's create a CSS file. Call it blog post page dot cs and now let's link to it we'll add the link tag and set rel
to style sheet and type text slash CSS and h ref to static CSS slash blog Post page dot CSS. Oh, actually, since these quotation marks are double quotations, these ones should be single quotations. Now let's open the CSS file and the first thing we want to do is give our blog post container a max width let's say 800 pixels but
this div only contains the page title so let's fix this and have it contain our entire blog post. So let's just fix that by adding the closing tag at the end. Okay, I think this should do it. So let's refresh. Okay, it worked. Now we want to center the blog post. So let's add margin. We can set it to 40 pixels auto and refresh. Yay, very cool. Now how about We add a background color to our post
and have it be something grayish as well. Okay. And add padding, let's say twenty pixels, and then border radius. Let's say eight pixels. Okay, I think that looks cool. But let's also add some box shadow. And now let's style the title So it's an H1 element with a page title. Let's give it the class title and that 's style. Title Text Align
Center. Alrighty. And let's make the color dark gray. Cool cool cool. And actually, let's make the entire post text color dark gray Let's fix what's going on here uh with the authors. So we have our authors in a div called Author info and author info is actually inside an unordered list. So we want to target the unordered list. So author info UL
and we want to set list style type to none because we don't want to see those black dots. Alright, cool. And now let's set display to flex and flex wrap to wrap. Okay, let's refresh. Cool. Now let's target the list item, which we've given the class author item. Let's give it also Display flex and make flex direction column refresh cool okay and now Let's add gap five
pixels and over here for the unordered list let's also add gap let's make ten pixels. Righty. Now let's target the gallery bit So we have given it the class gallery. Gallery And we want to set display to flex as well and set flex wrap to wrap. Okay, let's refresh, maximize, you see what happened, right? Um let's maybe add gap.
Let's make it 15 pixels Okay, I think that looks decent. Alrighty, let's take another look at our blog post. I feel like the background might be a bit too dark, and also I'm not loving the fact that our authors are pushed to the right. So let's first lighten the color of our background a bit. And refresh, yeah. I think that looks better. And to fix the position of the authors, we can add padding. zero to our unordered list. Okay, let's refresh. Yeah, that looks better.
Actually I like the color of the background. How about we copy it and we set the same color? for our thumbnails background. So in blog index page let's add This color instead. I'll just paste it. Okay, now let's go back to Turn to our blog. Yeah, I think this color looks a bit better. Actually, now that we're here, I feel like we could also increase the fun font size for the intro. So Let's add
font size one point one Ram Okay, let's refresh. Yeah, I think this looks good. Finally, let's take another look at our bag index page. It obviously needs to be centered. I'm thinking instead of creating a CSS file for it since we have given max width two. all our blog pages and we've centered them all, we could just go to our site. css, the CSS file that targets our entire website, and we could add Max width to the body and set it to 900 pixels and we could add
margin zero auto Alrighty, let's hit CtrlF5 to hard refresh and let's go to our tags page. And yay, it's centered. Let's try another tag And that's how it looks like. Of course we could add more styling. But I feel for now this is good. If we wanted to improve user experience, we could Tell them when was the last time a post was edited also. So we can do this by going back to our tag index page and actually let's close this Let's add a small element and have it say
revised on. Blacktail makes it so easy to show when a page was last revised with the Latest revision created at property. Actually, let's add a break element and let's go back and refresh And ta -da, we have the that last date of revision. Very cool, right? Okay, so another thing that Wagtail does for you when you create a Wagtail project is it creates a slash search page where you can search your site. Let's try to search for let's say Capibara
Right now it says no results found. Now if we wanted to be able to search certain fields, such as for example our blog post intro and our blog post body, then we're gonna need to index them and in order to index them all we gotta do is first import index from wagtail. search I'll copy the import statement And I'm gonna paste it in models. py where we have defined our blog post page And then all we gotta do is just override search fields and add the fields that we want to index to the search field list So
index. search field body and we also said we want to add the intro field. Alrighty, next up we should make sure that our search index is rebuilt so let's stop the server and we're going to use the command update index so pi manage Stop pie update index. Okay, cool. Now our index was updated. So let's restore server. Okay. And let's go back to our search and hard refresh. Yay! It showed the post that has capybara.
Now let's try something else, like for example, any moles. Alrighty, here it is. It showed the post that has animals. Now what if we wanted to add this search feature to our blog index page? Doing this is so easy because Wagtail already did all the hard work for us. If you guys remember when we created our project, it came with a search directory which is actually a search app and if we click on templates we will find there's search. html let's go to it And inside it there's a form. Let's copy this form and then let's go to blog index and let's put it above our blog title, for example.
Alrighty. And now let's refresh and let's go to our blog. And here is our search form. Now let's try to search for something. Let's, for example, search for Hippo And check it out. It redirected us to the search page and it found a blog post that have uh a blog post that has hippo and we can just click on it. Yeah Cool, right? Alrighty, I'm wondering if putting the form under the page title and description. would be better. So maybe here. Okay, let's refresh
Yeah, I think that looks better. If we wanted to we can give it some padding. Um since it's a form element we could just add styling to form, maybe add padding bottom, let's say five pixels. Okay, let's refresh. I think that looks better. Okay, let's try searching for something one last time. Let's search for nature. Yay. Cool. We did it guys. And we are almost almost almost done. But there is something that's bothering me a bit
and I want to tell you about it and about how easy it is to just change it. So right now if we go to our root page it says welcome to our awesome site and it doesn't redirect to the blog but it's so easy to add a redirect to blog with our Rich text field. Let's click on that bird and click on edit this page and let's add check out our blog and let's make blog bald and also let's make it a link and we want to link to our blog which we can just select like I just did
super easily and now it is a link So that's publish. That's view live. And now let's click on blog. And it redirects to the blog. Woo-hoo. Alrighty. Perhaps Making our tags look like buttons would be a big improvement. So let's go back to blog postpage. css And we have given the anchor element for the tags, the class tag. button so let's give it a background color of let's say
something bluish Make it let's make it I don't know this color maybe attard refresh and take a look at the color oh it looks like that now so how about we add padding let's say five pixels and also let's target The tags div and add margin five pixels as well. And let's make the color white and add border radius to make it rounded. Let's make it
five pixels And let's add an unhover effect. Let's change the background color to something slightly darker Yeah, like so. And also let's set text decoration to none on hover Yeah, that looks really cool. Alrighty, and for the return to block um anchor element above it, let's add class Return and let's give it padding
Spadding, let's say five pixels Yeah, that looks better. We could also give a font weight seven hundred. Yeah. Now it's clearer. And finally I feel like we need more space between the return to blog and the tags. So let's add margin top fifteen pixels to our tags div. Let's refresh. Yeah, I think that looks cool. And now just for fun
I would like to add some styling to the home page. So let's Go back to our homepage template, homepage. html, and let's override block extra CSS and in the static directory there's already welcome page. css. I'm going to just rename it to home. css and I'm gonna delete all the code in it and then I'll go to homepage. css and link to it. So link, rel, style sheet, Type
text slash CSS H R F static CSS slash home dot css. Alrighty and now I'm just gonna create a div element around the body and I'll give it the class container. Okay, and now let's add styling to container. Alrighty. So now let's Give container display flex flex direction column justify conent Center align items center margin zero auto
And now let's add a background color. Let's make it the same color that we have added to blog index. So I'll just copy it and Paste it. Let's make min height eighty view height and max width eight hundred. Now let's add border radius to make our edges rounded. Let's set it to 10 pixels and make the font bigger. So let's make font size let's say one point three Ram or maybe 1. 5
and set text aligned to center and let's add some box shadow And now let's change the color of the link. So container A, let's make color something bluish. Yeah, like this. And maybe we could add padding twenty pixels And margin top fifty pixels. Yeah, I think that looks cool Let's give our blog a final
review. Let's click on this post. Wait a minute. I thought we added captions to this particular particular post. I bet if we go back to blog post page. html we're gonna find a mistake. So where is the part where we render the caption? Yep Yes, I see the mistake. So when we were looping through images, I wrote page. caption instead of image. caption. Probably that's the culprit. Okay, let's go back and refresh. Yeah, here are the captions Alright guys, we did it. We created a blog website with a blog index page that lists blog posts and that allows you to search the blog posts. And of course we've created
blog detail page For every blog post complete with tags. So if we wanted to read blog posts tagged with, for example, wildlife, we'd click on the wildlife tag and We will see all the posts tagged with wildlife. It's been a pleasure coding with you. I hope you found this video useful and you've learned something new. If you have any questions or suggestions please type them down in the comments. And don't forget to like the video and subscribe if you haven't already. See you soon. Bye.
You need Python 3 installed, with a version compatible with Wagtail. The tutorial then creates and activates a virtual environment before installing Wagtail with pip.
Discussed at 2:21Create the project with `wagtail start`, install the generated requirements, and run `manage.py migrate`. Wagtail uses SQLite by default but also supports Django-compatible databases such as PostgreSQL, MariaDB, MySQL, and Oracle.
Discussed at 3:06Run `manage.py createsuperuser`, enter the username, email, and password, then start the server and visit `/admin` to log in with that account.
Discussed at 4:36Edit the homepage template, which extends a shared `base.html` template, and use Django template expressions such as `page.title` to display page fields. Shared HTML, CSS blocks, and boilerplate belong in the base template.
Discussed at 6:55Define a `RichTextField` in the page model, include it in `content_panels` with a `FieldPanel`, create and apply migrations, and render it in the template with Wagtail’s rich-text filter.
Discussed at 9:11Create an app with `manage.py startapp`, register it in `INSTALLED_APPS`, and define page models such as a blog index and blog post page inheriting from Wagtail’s `Page` model. The example adds fields for dates, introductions, bodies, authors, images, and tags.
Discussed at 13:50Create an orderable gallery model with a parental key to the blog post and foreign-key it to Wagtail’s image model. Add image and caption panels, then expose the gallery inline through the blog post’s `content_panels`.
Discussed at 18:29Place templates under the app’s `templates` directory, in a folder matching the app label, and name the file after the model in snake case—for example, `blog/blog_index_page.html`. The template should extend the shared `base.html` and put page content inside the `content` block.
Discussed at 33:56Create and publish a tag index page with the slug used in the tag links, add its expected HTML template, and override `get_context` to retrieve the URL’s `tag` parameter and filter blog posts by tag name. The template then loops through the filtered posts and links to each post.
Discussed at 56:54Note: 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