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.