既にロードされている単一のオブジェクトのストレートダンプをキャッシュする場合、はい、何も得られないか、ほとんど何も得られません。それはそれらの例が説明しているものではありません-それらは階層を説明しているので、何かより低いものへのいかなる変更も、階層のより上のすべてへの更新をトリガーするはずです。
37signalsブログの最初の例ではProject -> Todolist -> Todo
、階層として使用しています。入力された例は次のようになります。
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)
それで、Bang3
更新されたとしましょう。そのすべての親も更新されます:
Project: Foo (last_modified: 2014-05-16)
Todolist: Bar2 (last_modified: 2014-05-16)
Todo: Bang3 (last_modified: 2014-05-16)
次に、レンダリングの時間になるとProject
、データベースからのロードは基本的に避けられません。開始するにはポイントが必要です。ただし、これlast_modified
はすべての子のインジケーターであるため、子をロードする前にキャッシュキーとして使用します。
ブログの投稿では個別のテンプレートを使用していますが、私はそれらを1つにまとめます。1つの場所で完全なやり取りを確認すると、少しわかりやすくなります。
したがって、Djangoテンプレートは次のようになります。
{% 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 %}
cache_key
まだキャッシュに存在するプロジェクトを渡すとします。すべての関連オブジェクトへの変更を親に伝達するため、その特定のキーがまだ存在するという事実は、レンダリングされたコンテンツ全体をキャッシュからプルできることを意味します。
その特定のプロジェクトが更新されたばかりの場合(たとえば、Foo
上記のように)、その子をレンダリングする必要があり、その後、そのプロジェクトのすべてのTodolistsに対してクエリを実行します。同様に、特定のTodolistの場合-そのリストのcache_keyが存在する場合、リスト内のTodoは変更されておらず、すべてをキャッシュから取得できます。
またtodo.cache_key
、このテンプレートで使用していないことに注意してください。あなたが質問で言うように、それbody
はすでにデータベースからプルされているので、それは価値がありません。ただし、何かをキャッシュする理由はデータベースのヒットだけではありません。たとえば、生のマークアップテキスト(StackExchangeの質問/回答ボックスに入力するものなど)を取得してHTMLに変換するには、結果をキャッシュするのに十分な時間がかかる場合があります。
その場合、テンプレートの内部ループは次のようになります。
{% for todo in list.todos.all %}
{% cache 9999 todo todo.cache_key %}
<li>{{ todo.body|expensive_markup_parser }}</li>
{% endcache %}
{% endfor %}
すべてをまとめるために、この回答の上部にある元のデータに戻りましょう。仮定すると:
- すべてのオブジェクトは元の状態でキャッシュされていました
Bang3
更新されました
- 変更されたテンプレート(を含む
expensive_markup_parser
)をレンダリングしています
次に、これはすべてがロードされる方法です:
Foo
データベースから取得されます
Foo.cache_key
(2014-05-16)キャッシュに存在しません
Foo.todolists.all()
照会されています Bar1
し、Bar2
データベースから取得されます
Bar1.cache_key
(2014-05-10)キャッシュに既に存在します。それを取得して出力する
Bar2.cache_key
(2014-05-16)キャッシュに存在しません
Bar2.todos.all()
照会されています Bang3
し、Bang4
データベースから取得されます
Bang3.cache_key
(2014-05-16)キャッシュに存在しません
{{ Bang3.body|expensive_markup_parser }}
レンダリングされます
Bang4.cache_key
(2014-04-01)はすでにキャッシュに存在します。それを取得して出力する
この小さな例でのキャッシュによる節約は次のとおりです。
- データベースヒットを回避:
Bar1.todos.all()
expensive_markup_parser
:3回を避けBang1
、Bang2
、およびBang4
そしてもちろん、次に表示されたときにそれFoo.cache_key
が見つかるので、レンダリングするための唯一のコストはFoo
、データベースから単独で取得してキャッシュをクエリすることです。