Per memorizzare nella cache un dump diretto di un singolo oggetto già caricato, sì, non ottieni nulla o quasi nulla. Non è quello che descrivono quegli esempi: descrivono una gerarchia, in cui qualsiasi modifica a qualcosa di più basso dovrebbe anche innescare un aggiornamento a tutto ciò che è più in alto nella gerarchia.
Il primo esempio, dal blog 37signals, usa Project -> Todolist -> Todo
come gerarchia. Un esempio popolato potrebbe apparire così:
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)
Quindi, supponiamo che sia Bang3
stato aggiornato. Tutti i suoi genitori vengono anche aggiornati:
Project: Foo (last_modified: 2014-05-16)
Todolist: Bar2 (last_modified: 2014-05-16)
Todo: Bang3 (last_modified: 2014-05-16)
Quindi, quando arriva il momento del rendering, il caricamento Project
dal database è praticamente inevitabile. È necessario un punto per iniziare. Tuttavia, poiché last_modified
è un indicatore di tutti i suoi figli , è quello che usi come chiave della cache prima di tentare di caricare i figli.
Mentre i post del blog utilizzano modelli separati, li raggrupperò in uno solo. Speriamo che vedere la completa interazione in un posto lo renderà un po 'più chiaro.
Quindi, il modello Django potrebbe assomigliare a questo:
{% 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 %}
Supponiamo di passare a un progetto la cui cache_key
cache esiste ancora. Poiché propagiamo le modifiche a tutti gli oggetti correlati al genitore, il fatto che quella particolare chiave esista ancora significa che l' intero contenuto renderizzato può essere estratto dalla cache.
Se quel particolare Progetto fosse appena stato aggiornato - ad esempio, come Foo
sopra - allora dovrà renderizzare i suoi figli, e solo allora eseguirà la query per tutti i Todolisti per quel Progetto. Allo stesso modo per un Todolist specifico - se esiste la cache_key di quell'elenco, i todos al suo interno non sono cambiati e il tutto può essere estratto dalla cache.
Nota anche come non sto usando todo.cache_key
in questo modello. Non ne vale la pena, dal momento che come dici nella domanda, body
è già stato estratto dal database. Tuttavia, gli hit del database non sono l'unico motivo per cui potresti memorizzare nella cache qualcosa. Ad esempio, prendere il testo di markup non elaborato (come quello che digitiamo nelle caselle di domanda / risposta su StackExchange) e convertirlo in HTML potrebbe richiedere del tempo sufficiente a rendere più efficiente la memorizzazione nella cache del risultato.
Se così fosse, il ciclo interno nel modello potrebbe assomigliare di più a questo:
{% for todo in list.todos.all %}
{% cache 9999 todo todo.cache_key %}
<li>{{ todo.body|expensive_markup_parser }}</li>
{% endcache %}
{% endfor %}
Quindi, per mettere insieme tutto, torniamo ai miei dati originali nella parte superiore di questa risposta. Se assumiamo:
- Tutti gli oggetti erano stati memorizzati nella cache nel loro stato originale
Bang3
è stato appena aggiornato
- Stiamo eseguendo il rendering del modello modificato (incluso
expensive_markup_parser
)
Quindi è così che tutto sarebbe caricato:
Foo
viene recuperato dal database
Foo.cache_key
(2014-05-16) non esiste nella cache
Foo.todolists.all()
viene richiesto: Bar1
e Bar2
vengono recuperati dal database
Bar1.cache_key
(10-05-2014) esiste già nella cache ; recuperarlo ed emetterlo
Bar2.cache_key
(2014-05-16) non esiste nella cache
Bar2.todos.all()
viene richiesto: Bang3
e Bang4
vengono recuperati dal database
Bang3.cache_key
(2014-05-16) non esiste nella cache
{{ Bang3.body|expensive_markup_parser }}
è reso
Bang4.cache_key
(01-04-2014) esiste già nella cache ; recuperarlo ed emetterlo
I risparmi dalla cache in questo piccolo esempio sono:
- Hit del database evitato:
Bar1.todos.all()
expensive_markup_parser
evitate 3 volte: Bang1
, Bang2
, eBang4
E naturalmente, la prossima volta che Foo.cache_key
verrà visualizzato, verrebbe trovato, quindi l'unico costo per il rendering è recuperare Foo
da solo dal database e interrogare la cache.