Sometimes you don’t want to cache an entire page. You have a site where some things on the pages change every time the page is loaded. But you also don’t want to recreate expensive tasks that rarely change, such as the list of authors or topics. You can hook directly into the cacheing system using a template tag
Comment out (put a hash mark in front of) the two middleware.cache lines in MIDDLEWARE_CLASSES in settings.py, to disable per-page caching. Also, comment out the CACHE_MIDDLEWARE_SECONDS line, as it’s unnecessary.
At the very top of the parent template, add:
{% load cache %}
And around the video area, put: the cache tag:
{% cache 600 video %}
<h2>Video of the day!</h2>
{% embed "6ugx0Z0239Y" %}
{% endcache %}
This will cache that section of the template for a five minutes—600 seconds.
The {% cache %} template tag caches based on the name you give the tag. If you use that tag in multiple places, each place will share the same cache. So if you want to cache a posting in post.html, you can’t just say {% cache 120 post %}:
{% load cache %}
…
{% block content %}
{% cache 120 post %}
{{ post.content|linkTopics|linebreaks }}
{% include "parts/post_topics.html" %}
<p class="author">
{% if post.author.homepage %}
<a href="{{ post.author.homepage }}">{{ post.author }}</a>,
{% else %}
{{ post.author }}
{% endif %}
{{ post.date|date:"l, F jS, Y h:i a" }}
</p>
<div class="bio">{{ post.author.bio|linkTopics|linebreaks }}</div>
{% endcache %}
{% endblock %}
Try it, and you’ll see that for two-minute intervals, each post is exactly the same.
We need to give the {% cache %} tag another identifier to differentiate each post. For example, each of our posts has a unique slug, so we can use that as an identifier:
{% cache 120 post post.slug %}
…
{% endcache %}
If you try it now, each post will cache for two minutes, but will not pollute other posts with their cache.
The cache identifier is shared across pages, so if we want to cache the postings as they’re displayed on a listing page, we need to use a different identifier; “post_index” instead of “post”, for example. Modify index.html again:
{% block content %}
{% for post in postings %}
{% cache 120 post_index post.slug %}
<h2><a href="{% url postings.views.showPost post.slug %}">{{ post.title }}</a></h2>
<p class="author">{{ post.author }}, {{ post.date|date:"F jS, Y h:i a" }}</p>
{{ post.content|linkTopics|linebreaks }}
{% include "parts/post_topics.html" %}
{% endcache %}
{% endfor %}
{% endblock %}
The main page and the topics pages will now only regenerate each post entry if two minutes have past. And because we’re caching each post rather than the entire list (by putting “{% cache %}” around the for loop), new postings will still show up immediately. With per-page cacheing, new postings won’t show up until after the page’s cache expires.