Для кеширования прямого дампа одного уже загруженного объекта, да, вы ничего не получаете или почти ничего. Это не то, что описывают эти примеры - они описывают иерархию, где любое изменение чего-то более низкого также должно вызывать обновление всего более высокого в иерархии.
Первый пример из блога 37signals использует Project -> Todolist -> Todoв качестве иерархии. Заполненный пример может выглядеть так:
Project: Foo (last_modified: 2014-05-10)
Todolist: Bar1 (last_modified: 2014-05-10)
Todo: Bang1 (last_modified: 2014-05-09)
Todo: Bang2 (last_modified: 2014-05-09)
Todolist: Bar2 (last_modified: 2014-04-01)
Todo: Bang3 (last_modified: 2014-04-01)
Todo: Bang4 (last_modified: 2014-04-01)
Итак, скажем, Bang3был обновлен. Все его родители также получают обновления:
Project: Foo (last_modified: 2014-05-16)
Todolist: Bar2 (last_modified: 2014-05-16)
Todo: Bang3 (last_modified: 2014-05-16)
Затем, когда приходит время рендеринга, загрузка Projectиз базы данных в основном неизбежна. Вам нужно начать с. Однако, поскольку он last_modifiedявляется индикатором всех своих дочерних элементов , это то, что вы используете в качестве ключа кэша, прежде чем пытаться загрузить дочерние элементы.
Хотя сообщения блога используют отдельные шаблоны, я собираюсь объединить их в один. Надеюсь, увидев полное взаимодействие в одном месте, станет немного понятнее.
Итак, шаблон Django может выглядеть примерно так:
{% cache 9999 project project.cache_key %}
<h2>{{ project.name }}<h2>
<div>
{% for list in project.todolist.all %}
{% cache 9999 todolist list.cache_key %}
<ul>
{% for todo in list.todos.all %}
<li>{{ todo.body }}</li>
{% endfor %}
</ul>
{% endcache %}
{% endfor %}
</div>
{% endcache %}
Скажем , мы переходим в проекте которого до cache_keyсих пор существует в кэше. Поскольку мы распространяем изменения на все связанные объекты на родительский объект, тот факт, что этот конкретный ключ все еще существует, означает, что все визуализированное содержимое может быть извлечено из кэша.
Если этот конкретный проект был только что обновлен - например, как и Fooвыше - тогда он должен будет отобразить своих потомков, и только тогда он выполнит запрос для всех Todolist для этого проекта. Аналогично для конкретного Todolist - если существует ключ cache_key этого списка, то задачи внутри него не изменились, и все это можно извлечь из кэша.
Также обратите внимание, что я не использую todo.cache_keyв этом шаблоне. Это того не стоит, так как, как вы говорите в вопросе, bodyуже был извлечен из базы данных. Однако попадания в базу данных - не единственная причина, по которой вы можете что-то кэшировать. Например, взятие необработанного текста разметки (например, того, что мы вводим в поля вопросов / ответов в StackExchange) и преобразование его в HTML, может занять достаточно времени, чтобы кэширование результата было более эффективным.
Если бы это было так, внутренний цикл в шаблоне мог бы выглядеть примерно так:
{% for todo in list.todos.all %}
{% cache 9999 todo todo.cache_key %}
<li>{{ todo.body|expensive_markup_parser }}</li>
{% endcache %}
{% endfor %}
Итак, чтобы собрать все воедино, давайте вернемся к моим исходным данным в верхней части этого ответа. Если мы предположим:
- Все объекты были кэшированы в их первоначальном состоянии
Bang3 был только что обновлен
- Мы рендерим измененный шаблон (в том числе
expensive_markup_parser)
Тогда вот как все будет загружено:
Foo извлекается из базы данных
Foo.cache_key (2014-05-16) не существует в кеше
Foo.todolists.all()запрашивается: Bar1и Bar2извлекается из базы данных
Bar1.cache_key(2014-05-10) уже существует в кэше ; получить и вывести его
Bar2.cache_key (2014-05-16) не существует в кеше
Bar2.todos.all()запрашивается: Bang3и Bang4извлекается из базы данных
Bang3.cache_key (2014-05-16) не существует в кеше
{{ Bang3.body|expensive_markup_parser }} оказывается
Bang4.cache_key(2014-04-01) уже существует в кеше ; получить и вывести его
Экономия от кэша в этом крошечном примере:
- Избежание попадания в базу данных:
Bar1.todos.all()
expensive_markup_parserизбегали 3 раза: Bang1, Bang2иBang4
И, конечно, в следующий раз, когда он будет просмотрен, Foo.cache_keyон будет найден, поэтому единственная стоимость рендеринга - это получение в Fooодиночку из базы данных и запрос кеша.