FileBasedCache の使い方と仕組みについてメモします。
データベースを用意するまでもないけど、情報をキャッシュしたいときによさそうです。
ファイルで出力するのでキャッシュしたかどうか、キャッシュが残っているかどうかがわかりやすいためデバッグしやすい気がします。
また、キャッシュの中身も比較的簡単に確認できます。
動作環境
- MacBook Pro
- macOS Monterey
- Python 3.9.1
- Django 4.1.2
使い方
設定
設定ファイル (settings.py
, settings/*.py
など) でCACHESのバックエンド (BACKEND) とファイルの保存先 (LOCATION) を指定します。
LOCATIONは書き込み可能な場所を指定します。 ちなみに存在しないディレクトリでもapp側で作成します。
dockerの場合はvolumesで指定した場所の必要があります。 BASE_DIR ではなくroot近くの場所になりそうです。
CACHES = { 'default': { 'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache', 'LOCATION': BASE_DIR / 'tmp/django_cache', # 'KEY_PREFIX': 'prefix', } }
開発・本番といった複数のサーバーを起動していて、それぞれのキャッシュ結果を区別したい時は KEY_PREFIX
を設定できます。
キャッシュを保存・呼び出す
バックエンドの仕組みは関係なく、 django.core.cache.cache
からキャッシュを利用できます。
値のセットにはオプションとして timeout と version も設定できます。
cache.set(key, value, timeout=DEFAULT_TIMEOUT, version=None)
cache.get(key)
参考: Basic usage
FileBasedCache の仕組み
ソースコード ( django/filebased.py at main · django/django · GitHub ) を確認しながら仕組みを理解していきます。
実際に下記のようにキャッシュをセットしました。
cache.set('text', 'cache_text')
.djcache
ファイルが指定した保存場所に確認できます。
読み込み・書き込み権限はあるみたいです。
1つのkeyごとに1つのファイルが作成されます。
ls -al BASE_DIR/tmp/django_cache -rw------- 1 USER staff 49 Oct DD HH:MM 4720993faefa6c12c92c4b03540e3e17.djcache
ファイル名
この長いファイル名は MD5 で暗号化された key です。
ですが、そのままkeyを渡しただけでは再現しません。
from django.utils.crypto import md5 md5("text".encode(), usedforsecurity=False).hexdigest() '1cb251ec0d568de6a929b520c4aed8d1'
ファイル名のオプションとして prefix と version が指定できます。
つまり key, prefix, version の3つをフォーマットした文字列をファイル名とします。
フォーマット方法は KEY_FUNCTION で設定できますが、デフォルトでは django.core.cache.backends.base.default_key_func
を使っています。
具体的には "%s:%s:%s" % (key_prefix, version, key)
です。
keyprefix のデフォルトは ''
(空文字)、 versionのデフォルトは 1
なので、その通り試してみると無事ファイル名が再現しました。
md5(":1:text".encode(), usedforsecurity=False).hexdigest() '4720993faefa6c12c92c4b03540e3e17'
保存方法
.djcache
ファイルは読み込みできるようなので、value を確認します。
ファイルは timeout (expired) の情報 と value を持ちます。
timeout は pickle, value は pickle と zlib で圧縮しています。
その順に読み込むと数値 (エポック秒) とvalueが取得できました。
with open("BASE_DIR/tmp/django_cache/4720993faefa6c12c92c4b03540e3e17.djcache", "rb")as f: exp = pickle.load(f) value = pickle.loads(zlib.decompress(f.read())) print(exp, value) >> 16670XXXXX.XXXXX cache_text
ちなみにデフォルトのtimeoutは300 second なので、永続化の場合 None
を設定する必要があります
参考: TIMEOUT