Para armazenar em cache um despejo direto de um único objeto já carregado, sim, você ganha nada ou quase nada. Não é isso que esses exemplos estão descrevendo - eles estão descrevendo uma hierarquia, onde qualquer alteração em algo mais baixo também deve desencadear uma atualização para tudo o mais alto na hierarquia.
O primeiro exemplo, do blog 37signals, usa Project -> Todolist -> Todo
como hierarquia. Um exemplo preenchido pode ser assim:
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)
Então, digamos que Bang3
foi atualizado. Todos os seus pais também são atualizados:
Project: Foo (last_modified: 2014-05-16)
Todolist: Bar2 (last_modified: 2014-05-16)
Todo: Bang3 (last_modified: 2014-05-16)
Então, quando chega a hora de renderizar, o carregamento Project
do banco de dados é basicamente inevitável. Você precisa de um ponto para começar. No entanto, como last_modified
é um indicador de todos os filhos , é isso que você usa como chave de cache antes de tentar carregar os filhos.
Enquanto as postagens do blog usam modelos separados, vou agrupá-los em um. Esperamos que a interação completa em um só lugar a torne um pouco mais clara.
Portanto, o modelo do Django pode ser algo como isto:
{% 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 %}
Digamos que passamos em um projeto que cache_key
ainda existe no cache. Como propagamos alterações em todos os objetos relacionados ao pai, o fato de essa chave específica ainda existir significa que todo o conteúdo renderizado pode ser extraído do cache.
Se esse projeto em particular tivesse sido atualizado - por exemplo, como Foo
acima -, ele precisará renderizar seus filhos e só então executará a consulta de todos os todolistas desse projeto. O mesmo vale para uma Todolist específica - se a cache_key dessa lista existir, todos os que estão nela não serão alterados e a coisa toda poderá ser extraída do cache.
Observe também como não estou usando todo.cache_key
neste modelo. Não vale a pena, pois, como você diz na pergunta, body
já foi extraído do banco de dados. No entanto, as ocorrências no banco de dados não são a única razão pela qual você pode armazenar algo em cache. Por exemplo, pegar texto de marcação bruto (como o que digitamos em caixas de perguntas / respostas no StackExchange) e convertê-lo em HTML pode levar tempo suficiente para que o armazenamento em cache do resultado seja mais eficiente.
Se assim fosse, o loop interno no modelo pode parecer mais com isso:
{% for todo in list.todos.all %}
{% cache 9999 todo todo.cache_key %}
<li>{{ todo.body|expensive_markup_parser }}</li>
{% endcache %}
{% endfor %}
Então, para juntar tudo, vamos voltar aos meus dados originais na parte superior desta resposta. Se assumirmos:
- Todos os objetos foram armazenados em cache em seu estado original
Bang3
foi atualizado
- Estamos renderizando o modelo modificado (incluindo
expensive_markup_parser
)
Então é assim que tudo seria carregado:
Foo
é recuperado do banco de dados
Foo.cache_key
(16/05/2014) não existe no cache
Foo.todolists.all()
é consultado: Bar1
e Bar2
é recuperado do banco de dados
Bar1.cache_key
(10/05/2014) já existe no cache ; recupere e produza
Bar2.cache_key
(16/05/2014) não existe no cache
Bar2.todos.all()
é consultado: Bang3
e Bang4
é recuperado do banco de dados
Bang3.cache_key
(16/05/2014) não existe no cache
{{ Bang3.body|expensive_markup_parser }}
é processado
Bang4.cache_key
(01/04/2014) já existe no cache ; recupere e produza
As economias do cache neste pequeno exemplo são:
- Acerto no banco de dados evitado:
Bar1.todos.all()
expensive_markup_parser
evitados 3 vezes: Bang1
, Bang2
, eBang4
E, é claro, da próxima vez que for visualizado, Foo.cache_key
será encontrado, portanto, o único custo para renderizar é recuperar Foo
sozinho do banco de dados e consultar o cache.