Ja, wenn Sie einen geraden Speicherauszug eines einzelnen bereits geladenen Objekts zwischenspeichern, erhalten Sie nichts oder so gut wie nichts. Das beschreiben diese Beispiele nicht - sie beschreiben eine Hierarchie, bei der jede Änderung an etwas Niedrigerem auch eine Aktualisierung aller höheren Elemente in der Hierarchie auslösen sollte.
Das erste Beispiel aus dem 37signals-Blog wird Project -> Todolist -> Todo
als Hierarchie verwendet. Ein ausgefülltes Beispiel könnte folgendermaßen aussehen:
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)
Nehmen wir also an, es Bang3
wurde aktualisiert. Alle Eltern werden ebenfalls aktualisiert:
Project: Foo (last_modified: 2014-05-16)
Todolist: Bar2 (last_modified: 2014-05-16)
Todo: Bang3 (last_modified: 2014-05-16)
Wenn es dann Zeit zum Rendern ist, ist das Laden Project
aus der Datenbank grundsätzlich unvermeidlich. Sie brauchen einen Punkt, um anzufangen. Da last_modified
es sich jedoch um einen Indikator für alle untergeordneten Elemente handelt, verwenden Sie diesen als Cache-Schlüssel, bevor Sie versuchen, die untergeordneten Elemente zu laden.
Während die Blog-Beiträge separate Vorlagen verwenden, werde ich sie zu einer zusammenfassen. Hoffentlich wird die vollständige Interaktion an einem Ort etwas klarer.
Die Django-Vorlage könnte also ungefähr so aussehen:
{% 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 %}
Angenommen, wir übergeben ein Projekt, dessen cache_key
Cache noch vorhanden ist. Da wir Änderungen an allen zugehörigen Objekten an das übergeordnete Objekt weitergeben, bedeutet die Tatsache, dass dieser bestimmte Schlüssel noch vorhanden ist, dass der gesamte gerenderte Inhalt aus dem Cache abgerufen werden kann.
Wenn dieses bestimmte Projekt gerade aktualisiert wurde - beispielsweise wie Foo
oben -, muss es seine untergeordneten Elemente rendern und erst dann die Abfrage für alle Todolisten für dieses Projekt ausführen. Ebenso für eine bestimmte Todolist - wenn der cache_key dieser Liste vorhanden ist, haben sich die darin enthaltenen Aufgaben nicht geändert, und das Ganze kann aus dem Cache gezogen werden.
Beachten Sie auch, dass ich todo.cache_key
diese Vorlage nicht verwende . Es lohnt sich nicht, da, wie Sie in der Frage sagen, body
bereits aus der Datenbank gezogen wurde. Datenbanktreffer sind jedoch nicht der einzige Grund, warum Sie möglicherweise etwas zwischenspeichern. Wenn Sie beispielsweise rohen Markup-Text (z. B. das, was wir in StackExchange in Frage- / Antwortfelder eingeben) und in HTML konvertieren, kann dies ausreichend Zeit in Anspruch nehmen, damit das Zwischenspeichern des Ergebnisses effizienter ist.
In diesem Fall könnte die innere Schleife in der Vorlage folgendermaßen aussehen:
{% for todo in list.todos.all %}
{% cache 9999 todo todo.cache_key %}
<li>{{ todo.body|expensive_markup_parser }}</li>
{% endcache %}
{% endfor %}
Um alles zusammenzuführen, kehren wir zu meinen ursprünglichen Daten oben in dieser Antwort zurück. Wenn wir annehmen:
- Alle Objekte wurden in ihrem ursprünglichen Zustand zwischengespeichert
Bang3
wurde gerade aktualisiert
- Wir rendern die geänderte Vorlage (einschließlich
expensive_markup_parser
)
Dann würde so alles geladen:
Foo
wird aus der Datenbank abgerufen
Foo.cache_key
(2014-05-16) existiert nicht im Cache
Foo.todolists.all()
wird abgefragt: Bar1
und Bar2
werden aus der Datenbank abgerufen
Bar1.cache_key
(2014-05-10) existiert bereits im Cache ; Abrufen und Ausgeben
Bar2.cache_key
(2014-05-16) existiert nicht im Cache
Bar2.todos.all()
wird abgefragt: Bang3
und Bang4
werden aus der Datenbank abgerufen
Bang3.cache_key
(2014-05-16) existiert nicht im Cache
{{ Bang3.body|expensive_markup_parser }}
ist gerendert
Bang4.cache_key
(2014-04-01) existiert bereits im Cache ; Abrufen und Ausgeben
Einsparungen aus dem Cache in diesem winzigen Beispiel sind:
- Datenbanktreffer vermieden:
Bar1.todos.all()
expensive_markup_parser
vermieden 3 mal: Bang1
, Bang2
, undBang4
Und natürlich wird es beim nächsten Anzeigen Foo.cache_key
gefunden, sodass die einzigen Kosten für das Rendern darin bestehen, Foo
allein aus der Datenbank abzurufen und den Cache abzufragen.