6

次のように、Django キャッシュから単一のパスを削除しています。

from models                   import Graph
from django.http              import HttpRequest
from django.utils.cache       import get_cache_key
from django.db.models.signals import post_save
from django.core.cache        import cache

def expire_page(path):
    request      = HttpRequest()
    request.path = path
    key          = get_cache_key(request)
    if cache.has_key(key):   
        cache.delete(key)

def invalidate_cache(sender, instance, **kwargs):
    expire_page(instance.get_absolute_url())

post_save.connect(invalidate_cache, sender = Graph)

これは機能しますが、再帰的に削除する方法はありますか? 私のパスは次のようになります。

/graph/123
/graph/123/2009-08-01/2009-10-21

ID「123」のグラフが保存されるたびに、両方のパスのキャッシュを無効にする必要があります。これはできますか?

4

3 に答える 3

10

世代別キャッシュ戦略の採用を検討することをお勧めします。達成しようとしていることに適合するようです。提供したコードでは、絶対 URL ごとに「世代」番号を格納します。たとえば、「/graph/123」を初期化して世代を 1 にすると、そのキャッシュ キーは「/GENERATION/1/graph/123」のようになります。その絶対 URL のキャッシュを期限切れにしたい場合は、生成値を増やします (この場合は 2 にします)。そうすれば、次に誰かが「/graph/123」を検索すると、キャッシュキーは「/GENERATION/2/graph/123」になります。これにより、「/graph/123」と同じキャッシュキーを参照する必要があるため、すべてのサブページが期限切れになるという問題も解決されます。

最初は理解するのが少し難しいですが、これは非常に洗練されたキャッシュ戦略であり、正しく行えばキャッシュから実際に何も削除する必要がないことを意味します。詳細については、世代別キャッシングに関するプレゼンテーションをご覧ください。これは Rails 用ですが、言語に関係なく概念は同じです。

于 2010-01-28T18:08:41.060 に答える
1

もう 1 つのオプションは、キーのタグ付けとタグによるキーの削除をサポートするキャッシュを使用することです。Django の組み込みキャッシュ API は、このアプローチをサポートしていません。しかし、少なくとも 1 つのキャッシュ バックエンド (Django の一部ではない) がサポートされています。

DiskCache * は Apache2 ライセンスのディスクとファイルに基づくキャッシュ ライブラリであり、pure-Python で記述され、Django と互換性があります。プロジェクトで DiskCache を使用するには、インストールしてCACHES設定を構成するだけです。

インストールは簡単pipです:

$ pip install diskcache

次に、CACHES設定を構成します。

CACHES = {
    'default': {
        'BACKEND': 'diskcache.DjangoCache',
        'LOCATION': '/tmp/path/to/directory/',
    }
}

cacheメソッドは、次のようなsetオプションのキーワード引数によって拡張されます。tag

from django.core.cache import cache

cache.set('/graph/123', value, tag='/graph/123')
cache.set('/graph/123/2009-08-01/2009-10-21', other_value, tag='/graph/123')

diskcache.DjangoCacheは、内部でdiskcache.FanoutCacheを使用します。対応する FanoutCache は_cache属性を介してアクセスでき、evictメソッドを公開します。でタグ付けされたすべてのキーを/graph/123単純に削除するには:

cache._cache.evict('/graph/123')

アンダースコアの付いた属性にアクセスするのは面倒に感じるかもしれませんが、DiskCache プロジェクトは安定しており、DjangoCache実装に大きな変更を加える可能性は低いです。

Django キャッシュ ベンチマークページでは、代替キャッシュ バックエンドについて説明しています。

  • 免責事項: 私は DiskCache プロジェクトの最初の作成者です。
于 2016-03-21T18:08:50.667 に答える
-1

shutils.rmtree()またはos.removedirs( ) をチェックアウトします。最初はおそらくあなたが望むものだと思います。

いくつかのコメントに基づく更新: 実際には、Django のキャッシュ メカニズムは、キーに を使用するよりも一般的できめ細かくなっpathています (ただし、そのレベルで使用することはできます)。一部のページには、さまざまな基準に基づいて有効期限が切れる 7 つまたは 8 つの個別にキャッシュされたサブコンポーネントがあります。コンポーネント キャッシュ名は主要なオブジェクト (またはオブジェクト クラス) を反映し、特定の更新で無効にする必要があるものを識別するために使用されます。

すべてのページには、メンバー/非メンバーのステータスに基づいた全体的なキャッシュ キーがありますが、それはページの約 95% にすぎません。残りの 5% はメンバーごとに変更される可能性があるため、まったくキャッシュされません。

無効なアイテムを見つけるためにキャッシュをどのように反復処理するかは、それが実際にどのように格納されているかに依存します。単純にグロブおよび/または再帰的なディレクトリ削除を使用できるファイルの場合、他のメカニズムの場合は、別のものを使用する必要があります。

私の答えと他のコメントのいくつかが言おうとしているのは、キャッシュの無効化を達成する方法は、キャッシュの使用/保存方法と密接に関係しているということです。

2 番目の更新: @andybak: つまり、あなたのコメントは、私の商用 Django サイトがすべて炎上することを意味していると思いますか? それについて頭を上げてくれてありがとう。問題に対する回答を試みていないことに気付きました。

Knipknap の問題は、彼がキャッシュ アイテムのグループを持っていることです。これらのアイテムは、名前が原因で関連しているように見えますが、キャッシュ メカニズムのキー生成ロジックは、パス + vary_on の MD5 ハッシュを作成することによってその名前を消去します。元のパス/パラメーターの痕跡がないため、適切なグループが見つかることを期待して、考えられるすべてのパス/パラメーターの組み合わせを徹底的に推測する必要があります。もっと面白い趣味があります。

パスやパラメーター値の組み合わせに基づいてキャッシュされたアイテムのグループを検索できるようにする場合は、直接パターン マッチングできるキャッシュ キーを使用するか検索時に使用するためにこの情報を保持するシステムを使用する必要があります。

OPの問題と無関係ではないニーズがあったため、2年以上前にテンプレートフラグメントキャッシング、特にキー生成を制御しました。関連するキャッシュされたアイテムのグループを効率的に無効にするために、さまざまな方法で正規表現を使用できます。で構成可能なデフォルトのタイムアウトと vary_on 変数名 (実行時に解決される) も追加し、settings.py名前とタイムアウトの順序を変更しました。これは、フラグメントに名前を付けるためにデフォルトのタイムアウトを常にオーバーライドする必要があるのは意味がないためです。fragment_name を解決可能にしました。 (つまり、変数にすることができます)マルチレベルのテンプレート継承スキームと他のいくつかのものでよりうまく機能します。

私の最初の回答の唯一の理由は、現在の Django では実際に間違っていましたが、私が長い間健全なキャッシュ キーを使用してきたため、私たちが離れた単純なメカニズムを文字通り忘れていたからです。

于 2010-01-03T16:22:14.183 に答える