pythondjangopython-3.xdjango-viewsdjango-cache

Django delete cache with specific key_prefix


I'm using Django's per-view @cache_page decorator and have set a different key_prefix for each view.

I've previously deleted the cache with:

from django.core.cache import cache
cache.clear()

But what if I just want to delete the keys containing a specific key_prefix? I can obviously do it by just connecting to the database and delete with raw sql but I wonder if it can be done with 'pure' Django?

I'm using a database cache, not a memory cache.

I'm using Django 1.11 and Python 3.6


Solution

  • As @e4c5 mentioned cache is used for fast stuff, you should be using redis for the same. But since your question is about database I would answer the same.

    There is no existing function to do this in Django. But then best part of python is you can easily monkey path to add new functionality. Below is a test request I created

    def index(request):
        cache.set("name", "tarun")
        cache.set("name_1", "tarun")
        cache.set("name2", "tarun")
        cache.set("name_4", "tarun")
        cache.set("nam", "tarun")
    
        cache.clear(prefix="name")
        nam = cache.get("nam")
        name_4 = cache.get("name_4", default="deleted")
        return HttpResponse("Hello, world. nam={nam}, name_4={name_4}".format(nam=nam, name_4=name_4))
    

    Patched

    To get the prefix functionality you need to add below patch code in some place. I used settings.py as such

    original_clear = None
    
    
    def patch_clear():
        from django.db import connections, router
        from django.core.cache.backends.db import DatabaseCache
    
        def __clear(self, prefix=None, version=None):
            db = router.db_for_write(self.cache_model_class)
            connection = connections[db]
            table = connection.ops.quote_name(self._table)
            with connection.cursor() as cursor:
                if prefix is None:
                    cursor.execute('DELETE FROM %s ' % table)
                else:
                    prefix = self.make_key(prefix, version)
                    cursor.execute("DELETE FROM %s where cache_key like '%s%%'" % (table, prefix))
    
        global original_clear
        original_clear = DatabaseCache.clear
        DatabaseCache.clear = __clear
    
    patch_clear()