1

This problem has been bugging me all morning:

  • I have some views which accept GET params to modify the queryset (order_by and pagination) and cache it.
  • These views are very similar and they all share the same template.
  • These template caches a part of the page (taking the GET params into account) like this:

    {% with order=request.GET.order_by %}{% with page=request.GET.page %}{# I need them to set the cache name #}
    {% cache 7200 template urlname order page %}
    .... some part of the page...
    {% endcache %}
    {% endwith %}{% endwith %}{# with order and with page #}
    
  • Deleting the queryset cache is a piece of cake, but deleting the template cache has proven to be quite complicated. You usually need to generate the cache_key, like explained in the DOCS. The problem in my case is that I have to generate all the possible combinations of keys and delete them, which I'm doing like this:

    SITE_LIST_OPTIONS = [
        ('url', [reverse_lazy('site_list'),
                 reverse_lazy('best_site_list'),
                 reverse_lazy('banned_site_list'),
                 reverse_lazy('toreview_site_list')]),
        ('order', ['url', 'country', 'upstream_rank']),
        ('page', range(10))]
    
    
    def delete_cache_keys(keys):
        '''Deletes all the cache keys on the provided list.'''
        for e in keys:
            cache.delete(e)
    
    
    def delete_template_cache(key, filters=None):
        # first, we need to get all possible filter combination options
        if filters:
            options = combine_options(filters)
            keys = [make_template_fragment_key(key, ops) for ops in options]
            delete_cache_keys(keys)
        else:
            key = make_template_fragment_key(key, filters)
            cache.delete(key)
    
    # context_processor.py (used to generate key in template)
    
    def urlname(request):
        return {'urlname': resolve_urlname(request)}
    

I imagine I'm not the first person to ever try to cache templates based on GET params, so... is there a saner way to delete all the caches related to this particular template?

Edit: not sure why the formatting isn't showing up but here's a cleaner version just in case http://dpaste.org/XYYo2/

okm
  • 23,575
  • 5
  • 83
  • 90
la_f0ka
  • 1,773
  • 3
  • 23
  • 44

1 Answers1

0

You could group all cached snippets of a template, together by giving them a group cache key bound to the template. When you want to invalidate all of contents related to the template, you just clear the group key of the template:

>>> from django.core.cache import cache

>>> template_name = 'foo.html'
>>> cache.set(template_name, 1)
>>> make_group_key = lambda: '{name}-{version}'.format(
        name=template_name, version=cache.get(template_name))
>>> cache.set(make_group_key(), 'page content...')
>>> cache.get(make_group_key())
'page content...'

>>> cache.incr(template_name)
>>> cache.get(make_group_key()) is None
True

For your code, you could write a template tag which propagates the group key to context, like

{% get_template_key template as tmpl_key %}
{% cache 7200 template urlname order page tmpl_key %}

or you could generate the key in the view or somewhere else.

The delete part is then as simple as cache.incr(template_name) (You may need to deal w/ the exception that template_name no longer exists)

This method add an extra cache round-trip, but normally its fast enough.

okm
  • 23,575
  • 5
  • 83
  • 90
  • I think I'm missing some concept here. 1) I set a cache entry that holds the cache name??. 2)I set a cache key on the form of "template.html--content-of-template"?? How do I get this content? I mean,... the content is generated inside the template, right? – la_f0ka Mar 25 '13 at 15:47
  • @la_f0ka The first part of my post means to demonstrate the principle: storing a group key for all the snippets that are relative to the template. Then, whenever you want to invalidate all those snippets, just invalidate the group key. The cached snippets will still exist in the cache but eventually they will be discarded because of LRU algorithm. In your code, you need to add a variable `tmpl_key` to `{% cache ... %}`. The variable is constant until you decide to invalidate all the cached pages and have changed it. – okm Mar 26 '13 at 11:09
  • @la_f0ka ...From that time point, `{% cache ... %}` would generate keys different from those generated before by using the old `tmpl_key`, and previously cached snippets will be inaccessible and been cleared at last. – okm Mar 26 '13 at 11:10