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 -> Todoals 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 Bang3wurde 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 Projectaus der Datenbank grundsätzlich unvermeidlich. Sie brauchen einen Punkt, um anzufangen. Da last_modifiedes 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_keyCache 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 Foooben -, 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_keydiese Vorlage nicht verwende . Es lohnt sich nicht, da, wie Sie in der Frage sagen, bodybereits 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: Bar1und Bar2werden 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: Bang3und Bang4werden 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_parservermieden 3 mal: Bang1, Bang2, undBang4
Und natürlich wird es beim nächsten Anzeigen Foo.cache_keygefunden, sodass die einzigen Kosten für das Rendern darin bestehen, Fooallein aus der Datenbank abzurufen und den Cache abzufragen.