Pour mettre en cache un vidage direct d'un seul objet déjà chargé, oui, vous ne gagnez rien ou presque rien. Ce n'est pas ce que ces exemples décrivent - ils décrivent une hiérarchie, où tout changement vers quelque chose de plus bas devrait également déclencher une mise à jour de tout ce qui est plus haut dans la hiérarchie.
Le premier exemple, du blog 37signals, utilise Project -> Todolist -> Todo
comme hiérarchie. Un exemple rempli pourrait ressembler à ceci:
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)
Donc, disons a Bang3
été mis à jour. Tous ses parents sont également mis à jour:
Project: Foo (last_modified: 2014-05-16)
Todolist: Bar2 (last_modified: 2014-05-16)
Todo: Bang3 (last_modified: 2014-05-16)
Ensuite, quand vient le temps de rendre, le chargement à Project
partir de la base de données est fondamentalement inévitable. Vous avez besoin d'un point pour commencer. Cependant, comme last_modified
c'est un indicateur de tous ses enfants , c'est ce que vous utilisez comme clé de cache avant de tenter de charger les enfants.
Bien que les articles de blog utilisent des modèles distincts, je vais les regrouper en un seul. Espérons que voir l'interaction complète en un seul endroit le rendra un peu plus clair.
Ainsi, le modèle Django pourrait ressembler à ceci:
{% 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 %}
Supposons que nous transmettions un projet qui cache_key
existe toujours dans le cache. Étant donné que nous propagons les modifications de tous les objets associés au parent, le fait que cette clé particulière existe toujours signifie que tout le contenu rendu peut être extrait du cache.
Si ce projet particulier venait d'être mis à jour - par exemple, comme avec Foo
ci-dessus - alors il devra rendre ses enfants, et alors seulement il exécutera la requête pour tous les Todolists pour ce projet. De même pour une Todolist spécifique - si la clé cache_key de cette liste existe, alors les todos qu'elle contient n'ont pas changé, et le tout peut être extrait du cache.
Notez également comment je n'utilise pas todo.cache_key
dans ce modèle. Cela ne vaut pas la peine, car comme vous le dites dans la question, body
a déjà été retiré de la base de données. Cependant, les hits de base de données ne sont pas la seule raison pour laquelle vous pouvez mettre en cache quelque chose. Par exemple, prendre du texte de balisage brut (tel que ce que nous tapons dans des boîtes de questions / réponses sur StackExchange) et le convertir en HTML peut prendre suffisamment de temps pour que la mise en cache du résultat soit plus efficace.
Si tel était le cas, la boucle interne du modèle pourrait ressembler davantage à ceci:
{% for todo in list.todos.all %}
{% cache 9999 todo todo.cache_key %}
<li>{{ todo.body|expensive_markup_parser }}</li>
{% endcache %}
{% endfor %}
Donc, pour tout rassembler, revenons à mes données d'origine en haut de cette réponse. Si nous supposons:
- Tous les objets avaient été mis en cache dans leur état d'origine
Bang3
vient d'être mis à jour
- Nous rendons le modèle modifié (y compris
expensive_markup_parser
)
Ensuite, voici comment tout serait chargé:
Foo
est récupéré de la base de données
Foo.cache_key
(2014-05-16) n'existe pas dans le cache
Foo.todolists.all()
est interrogé: Bar1
et Bar2
sont récupérés de la base de données
Bar1.cache_key
(2014-05-10) existe déjà dans le cache ; récupérer et sortir
Bar2.cache_key
(2014-05-16) n'existe pas dans le cache
Bar2.todos.all()
est interrogé: Bang3
et Bang4
sont récupérés de la base de données
Bang3.cache_key
(2014-05-16) n'existe pas dans le cache
{{ Bang3.body|expensive_markup_parser }}
est rendu
Bang4.cache_key
(2014-04-01) existe déjà dans le cache ; récupérer et sortir
Les économies du cache dans ce petit exemple sont:
- Coup de base de données évité:
Bar1.todos.all()
expensive_markup_parser
3 fois évité: Bang1
, Bang2
etBang4
Et bien sûr, la prochaine fois qu'il sera visualisé, Foo.cache_key
il sera trouvé, donc le seul coût du rendu est la récupération Foo
seule de la base de données et l'interrogation du cache.