code: def cache_func(func, duration=conf.GOSCALE_CACHE_DURATION, cache_key=None):
          
      def do_cache(*args, **kwargs):
          alternative_cache_key = '%s.%s' %  (func.__module__, func.__name__)
          key = get_cache_key(cache_key, alternative_cache_key, *args, **kwargs)
          data = cache.get(key)
          if data: 
              return data
          data = func(*args, **kwargs)
          #in case a function is not False (implicit), so object couldn't be retrieved
          cache_duration = duration
          if not data:
              cache_duration = 1
          cache.set(key, data, cache_duration)
          return data
      return do_cache
docs: Django cache decorator for functions
      
      Basic ideas got from:
      - http://djangosnippets.org/snippets/492/
      - http://djangosnippets.org/snippets/564/
  
      Example usage:
  
      Example 1:
      - providing a cache key and a duration
      class MenuItem(models.Model):
          @classmethod
          @cache_func(, 3600*24, 'menu_root')
          def get_root(self):
              return MenuItem.objects.get(pk=1)
  
      Example 2:
      - providing a dynamic cache key and a duration
      @cache_func(3600, lambda u: 'user_privileges_%s' % u.username,)
      def get_user_privileges(user):
          #...
          
      Example 3:
      - providing only a duration of the cache, if no cache is provided it will
      be auto-generated
      @cache_func(1800)
      def get_page_by_absolute_url(url):
          #...