Per il caching di una copia dritta di un singolo oggetto già caricato, sì, non ottieni nulla o next-to-nothing. Questo non è ciò che descrivono questi esempi: stanno descrivendo una gerarchia, in cui qualsiasi modifica a qualcosa di inferiore dovrebbe anche innescare un aggiornamento a tutto ciò che è più in alto nella gerarchia.
Il primo esempio, dal blog 37signals, utilizza Project -> Todolist -> Todo
come gerarchia. Un esempio popolato potrebbe essere simile a questo:
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 diciamo che Bang3
è stato aggiornato. Anche tutti i suoi genitori vengono 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 di eseguire il rendering, il caricamento di Project
dal database è fondamentalmente inevitabile. Hai bisogno di un punto di partenza. Tuttavia, poiché il suo last_modified
è un indicatore di tutti i suoi figli , è quello che usi come chiave di cache prima di caricare i bambini.
Mentre i post del blog utilizzano modelli separati, ho intenzione di raggrupparli in uno solo. Spero che vedere l'interazione completa in un unico posto lo renderà un po 'più chiaro.
Quindi, il modello Django potrebbe essere simile 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 %}
Diciamo che passiamo in un Progetto il cui cache_key
esiste ancora nella cache. Poiché propagiamo le modifiche a tutti gli oggetti correlati al genitore, il fatto che questa particolare chiave esista ancora significa che interi contenuti renderizzati possono essere estratti dalla cache.
Se quel particolare progetto era stato appena aggiornato - per esempio, come con Foo
sopra - allora dovrà renderizzare i suoi figli, e solo allora eseguirà la query per tutti i Todol per quel progetto. Allo stesso modo per un Todolist specifico - se la cache_key di quell'elenco esiste, allora i file al suo interno non sono cambiati, e l'intera cosa può essere estratta dalla cache.
Notate 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'unica ragione per cui potresti memorizzare qualcosa. Ad esempio, prendere il testo di markup non elaborato (come quello che scriviamo in caselle di domanda / risposta su StackExchange) e convertirlo in HTML potrebbe richiedere un tempo sufficiente affinché la memorizzazione nella cache del risultato sia più efficiente.
Se così fosse, il ciclo interno nel modello potrebbe essere più simile 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 rimettere tutto insieme, torniamo ai miei dati originali nella parte superiore di questa risposta. Se ipotizziamo:
- Tutti gli oggetti sono stati memorizzati nella cache nel loro stato originale
-
Bang3
è stato appena aggiornato
- Stiamo rendendo il modello modificato (incluso
expensive_markup_parser
)
Quindi è così che tutto dovrebbe essere caricato:
-
Foo
è recuperato dal database
-
Foo.cache_key
(2014-05-16) non esiste nella cache
-
Foo.todolists.all()
viene interrogato: Bar1
e Bar2
vengono recuperati dal database
-
Bar1.cache_key
(2014-05-10) esiste già nella cache ; recuperalo e salvalo
-
Bar2.cache_key
(2014-05-16) non esiste nella cache
-
Bar2.todos.all()
viene interrogato: Bang3
e Bang4
vengono recuperati dal database
-
Bang3.cache_key
(2014-05-16) non esiste nella cache
-
{{ Bang3.body|expensive_markup_parser }}
è visualizzato
-
Bang4.cache_key
(2014-04-01) esiste già nella cache ; recuperalo e salvalo
I risparmi dalla cache in questo piccolo esempio sono:
- Risultato del database evitato:
Bar1.todos.all()
-
expensive_markup_parser
evitato 3 volte: Bang1
, Bang2
e Bang4
E, naturalmente, la prossima volta che viene visualizzato, verrà trovato Foo.cache_key
, quindi l'unico costo per il rendering è recuperare Foo
solo dal database e interrogare la cache.