Djangoフレームワークには、データをキャッシュする仕組みを抽象化、共通化したキャッシュフレームワークが含まれています。
Django's cache framework | Django ドキュメント | Django
どのようなキーと値が保存されるのか
キャッシュフレームワークのAPIで、どのようなキーと値がミドルウェアなどのバックエンドに保存されるのか確認してみます。
キャッシュに値を入れる
今回はDjango 5.0とredisバックエンドで試してみます。ローカル環境ではRedisが起動している想定。
myproject/settings.py:
CACHES = {
"default": {
"BACKEND": "django.core.cache.backends.redis.RedisCache",
"LOCATION": "redis://",
}
}
この設定でDjangoの manage.py shell
からキャッシュを保存します。
>>> from django.core.cache import cache
>>> cache.set("my-cache-key", "キャッシュの値")
>>> cache.get("my-cache-key")
'キャッシュの値'
キーと値を見てみる
保存できたら、 redis-cli
で確認してみます。
$ redis-cli # シェルからredis-cliを起動
127.0.0.1:6379> KEYS *
1) ":1:my-cache-key"
127.0.0.1:6379> GET :1:my-cache-key
"\x80\x05\x95\x19\x00\x00\x00\x00\x00\x00\x00\x8c\x15\xe3\x82\xad\xe3\x83\xa3\xe3\x83\x83\xe3\x82\xb7\xe3\x83\xa5\xe3\x81\xae\xe5\x80\xa4\x94."
まず、 KEYS <pattern>
コマンドでpatternに *
を指定し、すべてのキー一覧を取得しています。
:1:my-cache-key
という値がキーになっています。
settings.pyでキー生成の関数を設定していないので、デフォルトのDjangoのキー生成関数が使われています。
実装はこの辺です。
https://github.com/django/django/blob/617bcf611f3daa796e4054ba041089ece30a32fc/django/core/cache/backends/base.py#L40
return "%s:%s:%s" % (key_prefix, version, key)
key_prefix
は、settings.CACHESの各キャッシュの設定で KEY_PREFIX
キーにて変更できます。デフォルトは空文字列です。
version
settings.CACHESの各キャッシュの設定で VERSION
キーで指定できます。
https://github.com/django/django/blob/617bcf611f3daa796e4054ba041089ece30a32fc/django/core/cache/backends/base.py#L82
GET
コマンドで取得した値はバイナリ値になっています。これはDjango側のRedisバックエンドの中で、保存する値をpickleモジュールでシリアライズしているからです。
https://github.com/django/django/blob/617bcf611f3daa796e4054ba041089ece30a32fc/django/core/cache/backends/redis.py#L21
どのように値を保持するかは、キャッシュバックエンドごとで異なるので、シリアライズ・デシリアライズ処理を行うかどうかは、バックエンドクラスの実装次第です。
Djangoのキャッシュフレームワークを通してRedisに保存した値を、他のアプリなどから読み込んで使いたい場合、Pickleフォーマットだと扱いづらいかもしれません。その場合は自分でdumps, loadsメソッドを持ったクラスを実装するか、 json
モジュールなどを指定することもできます(この記事では手順は説明しません)
キー生成の関数を変更してみる
キーを生成する関数を変更するには、settings.pyのCACHESで KEY_FUNCTION
を設定します。
myproject/utils.py
def my_key_func(key, key_prefix, version):
return "spam:{}".format(key)
myproject/settings.py:
CACHES = {
"default": {
"BACKEND": "django.core.cache.backends.redis.RedisCache",
"LOCATION": "redis://",
"KEY_FUNCTION": "myproject.utils.my_key_func",
}
}
この設定の状態でキャッシュを manage.py shell
から追加してみます。
>>> from django.core.cache import cache
>>> cache.set("my-cache-key-2", "キャッシュの値")
>>> cache.get("my-cache-key-2")
'キャッシュの値'
redis-cliにてキーを見てみましょう。
$ redis-cli
127.0.0.1:6379> keys *
1) "spam:my-cache-key-2"
キー文字列が変わったことを確認できました。
ありそうな質問
キャッシュキーの一覧を取得したいですが、うまくいきません。どうすればよいですか?
Djangoのキャッシュフレームワークでは、キー一覧を返す仕組みを持っていません。この記事の例ではRedisの KEYS
コマンドを使用しています。
キャッシュを保存しておくバックエンドのミドルウェアがキーの一覧を返す仕組みを持たない場合もあります。キャッシュキーを検索したい要件がある場合は、キャッシュバックエンドの選定に気をつけるとよいでしょう。
cacheのすべてのkeyの取得の方法。
キャッシュを使っているのに本番環境が遅いです。ローカル環境では問題ないのになぜですか?
ネットワーク経由で外部キャッシュサーバーを使用している場合は、通信のレイテンシがあります。リクエスト内で何度もキャッシュを読み書きすると、遅くなる場合があります。複数のキーを指定してまとめて取得、まとめて更新する方法を使うと改善する可能性があります。
Djangoのcacheフレームワークで複数の値をまとめて取得、更新する - 偏った言語信者の垂れ流し