2

I am using Django's Template Fragment Caching so in a template.html file

{% extends 'base.html' %}
{% load cache %}
{% block content %}
  {% cache 500 "myCacheKey" %}
     My html here...
  {% endcache %}
{% endblock %}

This is working fine - I can see it's getting cached and hit but the view is doing something expensive to provide data to this view and thats getting called every time.

In views.py

def index(request)
   data = api.getSomeExpensiveData()
   return render_to_response('template.html', {'data':data} )

So how do I tell if the cache is avail before the call to api.getSomeExpensiveData()?

I can't use cache.get('myCacheKey') as the cache isn't found - does it use some naming scheme and if so can I either use something like

cache.get(cache.getTemplateFragmentKey("myCacheKey"))

or

cache.getTemplateFragment("myCacheKey")
Ryan
  • 23,871
  • 24
  • 86
  • 132
  • 1
    Maybe it would be better to implement a lazy data loading? Django uses this technique extensively. – Ski Jan 27 '11 at 20:23

2 Answers2

5

If you do not use that data in your view, something as simple as this might work:

def index(request)
   get_data = api.getSomeExpensiveData
   return render_to_response('template.html', {'get_data':get_data} )

In template

{% block content %}
  {% cache 500 "myCacheKey" %}
     {{ get_data.something }}
     Or maybe
     {% for something in get_data %}
     {% endfor %}
  {% endcache %}
{% endblock %}

Django template automatically calls all callable objects.

EDIT:

If you need to use get_data more than once in your template you'll need some wrapper. Something similar to this:

def index(request)
   class get_data(object):
       data = False
       def __call__(self):
           if not self.data:
               self.data = api.getSomeExpensiveData()
           return self.data
   return render_to_response('template.html', {'get_data':get_data()} )
Ski
  • 14,197
  • 3
  • 54
  • 64
  • Erm - thats more or less what I have now, but api.getSomeExpensiveData() is being called regardless of if the fragment is get from the cache (and hence the api call is not needed) or not. – Ryan Jan 27 '11 at 20:38
  • oops, I forgot to remove the `()`. But now I've understood that this is wrong, since you will want to get_data more than once in template. – Ski Jan 27 '11 at 20:43
  • Ohhh - gotcha, lazy loading +1 from me. – Ryan Jan 27 '11 at 20:52
  • Accepted as this is a better approach - ta! – Ryan Jan 27 '11 at 21:00
0

I found this SO - How do I access template cache?

And adapted it to

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

def hasFragmentCache(key, variables = []):
    hash = md5_constructor(u':'.join([urlquote(var) for var in variables]))    
    return cache.has_key(cache_key)

Edit - I've accepted skirmantas answer as whilst this does exactly as asked its the better approach as then the template and view are more loosly coupled. Using this method you need to know the name of each cache fragment and whats used where. A designer moves things around and it would fall over.

Community
  • 1
  • 1
Ryan
  • 23,871
  • 24
  • 86
  • 132