Для кеширования прямого дампа одного уже загруженного объекта, да, вы ничего не получаете или почти ничего. Это не то, что описывают эти примеры - они описывают иерархию, где любое изменение чего-то более низкого также должно вызывать обновление всего более высокого в иерархии.
Первый пример из блога 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
одиночку из базы данных и запрос кеша.