2

I have cache tag in the base template:

{% cache 100000 categories %}
    Categories output
{% endcache %}

When I add new category through Django admin, I want invalidate this cache:

class CategoriesAdmin(admin.ModelAdmin):
    def save_model(self, request, obj, form, change):
        super(CategoriesAdmin, self).save_model(request, obj, form, change)

        cache.delete('categories')

But the cache is stay valid! What is wrong?

Deadly
  • 2,034
  • 6
  • 24
  • 32

2 Answers2

3

That's because the actual key is not "categories", but rather one that's dynamically constructed by Django using the following:

args = md5_constructor(u':'.join([urlquote(resolve_variable(var, context)) for var in self.vary_on]))
cache_key = 'template.cache.%s.%s' % (self.fragment_name, args.hexdigest())

See: https://code.djangoproject.com/browser/django/tags/releases/1.3.1/django/templatetags/cache.py

In general, the key is going to be in the format: template.cache.categories.[hexdigest]. So the tricky part is figuring out the hexdigest part.

I found the following Django snippet (in the comments), which looks like it should still work (from 2009):

from django.core.cache import cache
from django.utils.hashcompat import md5_constructor
from django.utils.http import urlquote

def invalidate_template_cache(fragment_name, *variables):
    args = md5_constructor(u':'.join([urlquote(var) for var in variables]))
    cache_key = 'template.cache.%s.%s' % (fragment_name, args.hexdigest())
    cache.delete(cache_key)

Since you're not passing any variables to vary on to the templatetag, you can call that with just: invalidate_template_cache('categories'). Otherwise, you'd need to pass in a list of all the variables the template tag varies on as the second argument.

Chris Pratt
  • 232,153
  • 36
  • 385
  • 444
  • Thanks, that works fine! Why does it still not in native Django functions! – Deadly Mar 05 '12 at 16:25
  • 2
    In Django 1.4.X the md5_constructor is not used and you have to use hashlib instead. args = hashlib.md5(u':'.join([urlquote(resolve_variable(var, context)) for var in self.vary_on])) – margusholland Jan 07 '13 at 07:48
0

In Django 1.6+ please use make_template_fragment_key:

django.core.cache.utils.make_template_fragment_key(fragment_name, vary_on=None) If you want to obtain the cache key used for a cached fragment, you can use make_template_fragment_key. fragment_name is the same as second argument to the cache template tag; vary_on is a list of all additional arguments passed to the tag. This function can be useful for invalidating or overwriting a cached item, for example:

from django.core.cache import cache
from django.core.cache.utils import make_template_fragment_key
# cache key for {% cache 500 sidebar username %}
key = make_template_fragment_key('sidebar', [username])
cache.delete(key) # invalidates cached template fragment

Works like magic :-)