def cache_func(func, duration=conf.GOSCALE_CACHE_DURATION, cache_key=None):
    """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):
        #...
    """    
    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