def get_by(self, field_name, field_value, cache_timeout=None):
        """A convienence function for looking up an object by a particular field

        If the object is in the cache, returned the cached version.
        If the object is not in the cache, do a basic .get() call and store it in the cache.

        Fields used for lookup will be stored in the special cache, '__cached_field_names__'
        so they can be automatically purged on the object's flush_cache() method
        """
        if cache_timeout is None:
            cache_timeout = getattr(settings, 'CACHE_TIMEOUT', 900)

        # cache the field name that was used so flush_cache can purge them automatically
        key = self.model.cache_key("__cached_field_names__")
        cached_field_names = cache.get(key)
        if cached_field_names is None:
            cached_field_names = set()
        cached_field_names.add(field_name)
        cache.set(key, cached_field_names, cache_timeout)

        key = self.model.cache_key("by_" + field_name, field_value)
        obj = cache.get(key)
        if obj is None:
            obj = self.get(**{field_name: field_value})
            cache.set(key_function_memcache_compat(key), obj, cache_timeout)
        return obj
 def cache_key(cls, *args):
     """
     Generates a cache key from the object's class.__name__ and the arguments given
     """
     vals = [cls.__name__] + [key_function_memcache_compat(arg) for arg in args]
     return '_'.join(vals)