Para almacenar en caché un volcado directo de un solo objeto ya cargado, sí, no gana nada o casi nada. Eso no es lo que esos ejemplos están describiendo: están describiendo una jerarquía, donde cualquier cambio a algo más bajo también debería desencadenar una actualización de todo lo que está más arriba en la jerarquía.
El primer ejemplo, del blog 37signals, se usa Project -> Todolist -> Todo
como jerarquía. Un ejemplo poblado podría verse así:
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)
Entonces, digamos que Bang3
se actualizó. Todos sus padres también se actualizan:
Project: Foo (last_modified: 2014-05-16)
Todolist: Bar2 (last_modified: 2014-05-16)
Todo: Bang3 (last_modified: 2014-05-16)
Luego, cuando llega el momento de renderizar, la carga Project
desde la base de datos es básicamente inevitable. Necesitas un punto para comenzar. Sin embargo, debido a que last_modified
es un indicador de todos sus elementos secundarios , eso es lo que utiliza como clave de caché antes de intentar cargar los elementos secundarios.
Si bien las publicaciones del blog usan plantillas separadas, las agruparé en una sola. Con suerte, ver la interacción completa en un lugar lo hará un poco más claro.
Entonces, la plantilla de Django podría verse así:
{% 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 pasamos un proyecto cuyo cache_key
todavía existe en el caché. Debido a que propagamos los cambios a todos los objetos relacionados al padre, el hecho de que esa clave en particular aún exista significa que todo el contenido renderizado se puede extraer de la memoria caché.
Si ese Proyecto en particular acaba de actualizarse, por ejemplo, como en el caso Foo
anterior, tendrá que representar a sus hijos, y solo entonces ejecutará la consulta para todos los Todolistas para ese Proyecto. Del mismo modo para un Todolist específico: si la clave_caché de esa lista existe, entonces los todos dentro de ella no han cambiado, y todo se puede extraer de la caché.
Observe también cómo no estoy usando todo.cache_key
en esta plantilla. No vale la pena, ya que como dices en la pregunta, body
ya se ha retirado de la base de datos. Sin embargo, los accesos a la base de datos no son la única razón por la que puede almacenar algo en caché. Por ejemplo, tomar texto de marcado sin formato (como lo que escribimos en los cuadros de preguntas / respuestas en StackExchange) y convertirlo a HTML puede llevar suficiente tiempo para que el resultado del almacenamiento en caché sea más eficiente.
Si así fuera, el bucle interno de la plantilla podría verse más así:
{% for todo in list.todos.all %}
{% cache 9999 todo todo.cache_key %}
<li>{{ todo.body|expensive_markup_parser }}</li>
{% endcache %}
{% endfor %}
Entonces, para reunir todo, volvamos a mis datos originales en la parte superior de esta respuesta. Si suponemos:
- Todos los objetos habían sido almacenados en caché en su estado original.
Bang3
acaba de actualizarse
- Estamos renderizando la plantilla modificada (incluida
expensive_markup_parser
)
Entonces así es como se cargaría todo:
Foo
se recupera de la base de datos
Foo.cache_key
(2014-05-16) no existe en el caché
Foo.todolists.all()
se consulta: Bar1
y Bar2
se recuperan de la base de datos
Bar1.cache_key
(2014-05-10) ya existe en el caché ; recuperarlo y sacarlo
Bar2.cache_key
(2014-05-16) no existe en el caché
Bar2.todos.all()
se consulta: Bang3
y Bang4
se recuperan de la base de datos
Bang3.cache_key
(2014-05-16) no existe en el caché
{{ Bang3.body|expensive_markup_parser }}
se representa
Bang4.cache_key
(2014-04-01) ya existe en el caché ; recuperarlo y sacarlo
Los ahorros del caché en este pequeño ejemplo son:
- Se evitó el impacto en la base de datos:
Bar1.todos.all()
expensive_markup_parser
evitadas 3 veces: Bang1
, Bang2
yBang4
Y, por supuesto, la próxima vez que Foo.cache_key
se vea , se encontrará, por lo que el único costo para renderizar es recuperar Foo
solo de la base de datos y consultar el caché.