Wagtail CMS: Using the save() method to remove template fragment caching

This video is from Wagtail CMS 2023 .

Wagtail CMS: Using the save() method to remove template fragment caching
0:14:13
Published November 29, 2023
2,180 views

In the previous lesson we discovered how to save sections of a template and reduce the number of queries on any given page in our Wagtail website. But to delete the cache so that Wagtail CMS could update the page was a very manual task. In this tutorial, we'll learn how to use Wagtails save() method to delete specific template fragment cache from our site.

Tutorial: https://learnwagtail.com/tutorial/using-wagtails-save-method-to-remove-template-caching/

Git Commit: https://github.com/CodingForEverybody/learn-wagtail/commit/f9423929d815f8c3c960b849a57b606728aace0c

How to Add Template Caching: https://www.youtube.com/watch?v=TjTneEpBhEI

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

Summary

Wagtail’s template fragment cache does not change when a page’s title, subtitle, slug, or other displayed data is edited, so stale content and links can remain visible. The speaker shows how to override a page model’s `save()` method, call the parent implementation, generate the matching cache key with Django’s `make_template_fragment_key()`, and remove it with `cache.delete()`. Cache fragments keyed by a page ID should pass `self.id` as the identifying parameter; fragments without parameters, such as navigation, need only their cache name. This lets saved content invalidate the relevant fragment automatically without requiring a separate cache service such as Redis.

Key takeaways

  • Override the relevant Wagtail page model’s `save()` method so cache invalidation happens whenever the page is saved.
  • Use `make_template_fragment_key()` with the fragment name and the same parameters used in the template cache tag.
  • Delete the generated key through Django’s cache with `cache.delete()` after saving the page.
  • Pass `self.id` or other identifiers for per-object fragments, and omit the parameter list for fragments with no identifiers.
  • The same approach can invalidate shared fragments such as cached site navigation.

Summarised automatically from the transcript.

Transcript

2,287 words · auto-generated Show

Automatically transcribed, so expect mistakes in names and technical terms.

0:00

Hello and welcome back to another lesson on learning Wagtail. In the previous video, we talked about template caching. Technically it's fragmented template caching, so we could cache just certain parts of our template, and in this video we're going to learn how to get rid of that automatically, and we're going to use a Wagtail method on a page to do that. So before anything, what I'm going to have to do is open up my dev. py and uncomment my cache here. And I'm gonna copy where is this copy my path so that I have the correct path in here And it should be my site cache. And that's just going to live up in here in this in this folder in here with these different cache files.

0:49

The next thing I need to do is obviously start up my server. So I'm already in there, so let's do pip env python3 manage. py run server. This will run on port 8000. And when I open up my browser we have HTTP localhost 8000. So let's head on over to our super cool blog, and this is what we're going to be working with today. is when caching is enabled, we cannot change this. And if you're just stepping in and you haven't watched the previous video, let's take a look at what I'm talking about. In our blog detail page, we have a for loop in here. Where is my cache? I'm not even in the right file. In my blog listing page, that's better.

1:36

And I'm already on that line. So we are looping through every post that we have. It's paginated and we are going to loop through every post and cache every section. So what we're talking about is this entire section here. And then this entire section, and then on page two, same thing right here and right there. So those are all cached separately Now if we go ahead and we try to log in and change this title, we're going to see that it does not change. So let's go ahead open up localhost 8000 slash admin. And which page was that? Custom video blog title. Okay, let's do video. Custom video blog title.

2:22

Custom video blog title. This is the article we want to customize. So let's do this. Change this title, please. And we're going to run into a problem, which we actually ran into in the previous video as well, was caching. Well the thing with caching is it's always cached, right? It will stay the same until you tell it to be different. And we haven't told it to be different. So when I refresh this page, custom video blog title does not change. Now this is this can actually be a bigger problem. If we go back into this article and We changed our slug, then this page is not this this link rather on this page is not going to go to the right place. We need that to change. So in order to change that, all we have to do is add a save method to our Wagtail pages.

3:12

So if we open up blogmodels. py and we have Not a blog author, that's an orderable blog category, not necessary. We are looking for Blog listing page. Here it is. We've got a blog listing page. It's a routable page. It's a Wagtail page. It has a template, custom title. One custom title, that's it. That's all this one gets for blog listing page. Uh but that's actually not the one we want. So this is going to get a little bit tricky at first. And even though that this data lives on the blog listing page, we actually don't need to change that. What we want to do is when this page, this page.

3:59

our uh changes title please or the video blog article when that page is saved then we need to go and change this fragmented cache piece So what we want is when you save this page with a new title, we want to refresh just this one little chunk here. And The way that we can do that is if we go down to our blog detail page, we can actually put a save method on this blog post page And because the blog detail page, this one up here, I'm going to scroll up, where it says blog detail page, and it's inheriting from a Wagtail page. We come back down. We've got an article blog page. It's inheriting from our custom blog detail page. We have one more in here, a video blog page. Now what I'm going to do is because I don't really care which

4:48

child page it goes into. I want to make sure that the parent page always has this save method. So just so we're all on the same page, I'm on the blog detail page and I'm gonna scroll down and I'm just gonna put this at the bottom here. I'm gonna going to write a new function. I'm actually gonna make that move up and a little bigger. There we go Uh def, save, because it's an object. It's a class that always takes self as its first argument, and then args and keyword args. The last thing I want to do, because I often don't write code in order, is I want to run super, save, pass in args, and quargs.

5:33

And so this basically says in the save method here, before this bubbles up to Wagtail 's save method, that comes from the class called page, page. save. We want to execute something additional. And so what we're going to do here is we're just going to delete the cache. So the first thing we need to do is we need to make our key because If I close that, we can see that in our cache folder on the right here, we have these weird hash files And we have no idea how to generate that key. No idea at all. And honestly, we don't need to know how. We just need to know that there is some sort of key. There's some sort of magic method that will do it for us.

6:18

It'll make that key for us and all we have to do is then cache dot delete and then key So we are actually already halfway there. All we have to do is add in a function called makeTemplateFragment Key. And this is going to take the name of our cache and any additional parameters. So again, if we open up that blog listing page, in your cache template tag The first parameter is how long to cache it for in seconds. The second parameter is the name. And the third parameter, which could actually go on and on and on and on. We could have more parameters in here, are additional parameters So we are grabbing that post ID. So this is the name and this is the unique identifier.

7:07

So we want to grab that name called blog post preview. That is a string. And then as a list, we just want to pass in self. id. Now where I'm getting self. id from is this blog detail page. That's the ID. And where I'm getting post. id from is the same thing. The blog post. It's just getting the ID. It just happens to be that instead of called self, because this is on a listing page, it is called post, because it's looping through all of our blog posts. So I'm just gonna scroll back down here and clean this up. Maybe maybe put that on one line if possible so you can quickly see what that looks like.

7:54

In fact, let's let's put that on separate lines. This is going to be a little more manageable if it's on separate lines So we've generated our key. We told it which name to look for and which parameters to look for. And then we said, hey cash, go and delete that. Now when I save this, I should run into an issue. Uh cache does not exist and make template fragment also does not exist. So let's scroll back up to the top And let's import these. So these come from Django Core. Django Core. cache. Let's import from Django. core. cache. Import cache. And also from Django

8:40

dot core dot cache dot utils import Make template fragment key. Okay, so I'm gonna go back down here And that looks okay, so let's open up our terminal. There's no complaints in there. And just uh I'm I'm gonna add one more little example in here. So anytime you save this page, it's also going to print something really ugly So it's going to print hello world. I am I am saving. And let's print that a bunch of times. Now let's open up our browser. Refresh and all I'm going to do is click publish and we are going to see that

9:26

okay it saved perfectly fine and in our terminal hello world I am saving So we know that our method, our method, where was it? Our save method is actually executing, and that this template this template fragment rather, should have been deleted successfully. There were no errors. So let's go ahead and open up Firefox again and let's refresh our listing page. Ta -da! And so anytime you change this, this is going to work. So let's go ahead and say title number one And let's also delete custom article, not delete, let's change. Custom article blog page title. Welcome to my subtitle.

10:12

Let's actually just change that subtitle in there Yeah, what's that one called? Custom article blog page. Article blog page. And where is it? Subtitle, there it is. Welcome to my subtitle. This subtitle is no longer cached. And refresh our page. We have title number one and our subtitle is no longer cache. So now we have automated our template fragment caching. Anytime you save this page, this is going to go and recreate that template fragment key, and it's going to delete it for you. Now you don't have to stick with this on just listing pages.

10:57

This can be used on detail pages. This can be used anywhere else. For example, let's open up uh I think it's base. Base. html. Yep. Perfect. So we've got caching in here for our navigation. We could delete that as well. So anytime Anything is updated, we could delete the navigation, and all we would have to do is open up our models. py. I'm gonna copy this whole thing over. I'm not gonna save this, I'm just going to show you what this can do without a parameter. So in our navigation, we called it navigation, it's cached for one week, that's 604 ,800 seconds using the cat the cache template tag And all we're gonna say is that.

11:42

So we're going to make a template fragment key from the word navigation. That's going to match this word in here. There's no parameters after this, so we're not going to put any parameters in a list after that. And then we're going to delete it. So that's all there is to it. So if you're working with template caching that does not have any additional data. Any additional identifiers for what your fragment should be cached as. What I'm talking about is this post ID. If there is no post ID or anything else in there. You can simply ignore this parameter. Don't put it in a list, just ignore the list entirely. So again, I'm going to I'm going to delete that. Because that's not necessary. And really that's all there is to know about deleting template fragments or template cache.

12:33

If you just wanted to delete one section, just put the name. If you wanted to delete a section that has a unique identifier or multiple unique identifiers, you could put the unique identifier in there. You could put The other one in here, maybe it's one, two, three, and the other one is four, five, six. You just have to make sure that it's uh in this one it would be self. id, one, two, three, four, five, six. So it looks something like that. And I'm just gonna undo that. And yep, that's all there is. So it's nice and easy. Again, template fragment caching is a really powerful way to speed up your website

13:18

without having to install any other applications like Redis. So if you're brand new to the the the Python environment or you don't really understand caching completely yet but you notice that your site's a little bit slow, this is a this is a perfect way to speed up your website. If you want to tinker around with this code, you can always find it in the git commit. The link is in the description down below My name is Caleb Tallin. I am an author on learnwagtail. com where you can find all of these videos and other tutorials about learning Wagtail. If you like this video, if this video helped you out, don't forget you can share, you can subscribe, and you can comment. Or you can click the link in the top right to open up the entire Learn Wagtail playlist. And you can scroll through all the different lessons if you wanted to. They all have the code available in the descriptions with them.

14:06

And lastly, I hope you learned something useful in this video, and I look forward to seeing you in the next one

Questions this talk answers

How do I automatically clear a Wagtail template fragment cache when a page is saved?

Override the page’s `save()` method, call the parent save method, generate the fragment-cache key, and delete it with Django’s cache API. Put the method on the shared parent page class so it applies to its child page types.

Discussed at 4:48

How do I generate the cache key for a Django template fragment?

Use Django’s `make_template_fragment_key()` with the cache fragment name and a list of the same identifying parameters used by the `{% cache %}` tag. For the blog preview, the key uses `blog post preview` and the page’s ID.

Discussed at 6:18

Can I use this technique to clear cached fragments on detail pages or other parts of a site?

Yes. The same approach works for detail pages and any other cached fragment, including site navigation; use the fragment name alone when there are no identifiers, or include every identifier when the fragment varies by data.

Discussed at 10:57

How do I invalidate a cached template fragment that has no unique parameters?

Pass only the fragment name to `make_template_fragment_key()` and omit the parameter list. For example, a navigation fragment cached as `navigation` can be deleted by generating a key from that name and calling `cache.delete()`.

Discussed at 11:42

Note: 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.

More videos from Wagtail CMS