Reputation: 18705
I'm trying to create my own decorator based on @cache_page decorator. My decorator should work exactly like @cache_page except when slug
attribute of the view matches request.user.userprofile
slug, then normally process the view and return not cached response
Pseudocode:
def profile(request,slug):
# if not request.user = User.objects.get(userprofile__slug=slug):
# return cache
# else compute response and return it
My decorator:
def exclude_cache_for_request_user(*args, **kwargs):
def exclude_cache_for_request_user_decorator(func):
def func_wrapper(*fargs,**fkwargs):
request = fargs[0]
if request:
user = getattr(request,'user',None)
owner_slug = fkwargs.get('slug')
owner = User.objects.get(userprofile__slug=owner_slug)
if user==owner:
return func(*fargs, **fkwargs)
else:
if len(args) != 1 or callable(args[0]):
raise TypeError("cache_page has a single mandatory positional argument: timeout")
cache_timeout = args[0]
cache_alias = kwargs.pop('cache', None)
key_prefix = kwargs.pop('key_prefix', None)
if kwargs:
raise TypeError("cache_page has two optional keyword arguments: cache and key_prefix")
return decorator_from_middleware_with_args(CacheMiddleware)(
cache_timeout=cache_timeout, cache_alias=cache_alias, key_prefix=key_prefix
)
return func_wrapper
return exclude_cache_for_request_user_decorator
This works if user matches the slug. Otherwise, it raises:
Exception Value:
'function' object has no attribute 'get'
Full traceback:
File "/home/milano/.virtualenvs/beduenovenv/local/lib/python2.7/site-packages/django/core/handlers/exception.py" in inner
41. response = get_response(request)
File "/home/milano/.virtualenvs/beduenovenv/local/lib/python2.7/site-packages/django/utils/deprecation.py" in __call__
142. response = self.process_response(request, response)
File "/home/milano/.virtualenvs/beduenovenv/local/lib/python2.7/site-packages/django/middleware/clickjacking.py" in process_response
32. if response.get('X-Frame-Options') is not None:
Exception Type: AttributeError at /profiles/detail/cingo/
Exception Value: 'function' object has no attribute 'get'
Do you know where is the problem? The best would be if there were caching for user and other users separately. So 2 caches for this view.
EDIT: This is an original @cache_page
decorator
def cache_page(*args, **kwargs):
"""
Decorator for views that tries getting the page from the cache and
populates the cache if the page isn't in the cache yet.
The cache is keyed by the URL and some data from the headers.
Additionally there is the key prefix that is used to distinguish different
cache areas in a multi-site setup. You could use the
get_current_site().domain, for example, as that is unique across a Django
project.
Additionally, all headers from the response's Vary header will be taken
into account on caching -- just like the middleware does.
"""
# We also add some asserts to give better error messages in case people are
# using other ways to call cache_page that no longer work.
if len(args) != 1 or callable(args[0]):
raise TypeError("cache_page has a single mandatory positional argument: timeout")
cache_timeout = args[0]
cache_alias = kwargs.pop('cache', None)
key_prefix = kwargs.pop('key_prefix', None)
if kwargs:
raise TypeError("cache_page has two optional keyword arguments: cache and key_prefix")
return decorator_from_middleware_with_args(CacheMiddleware)(
cache_timeout=cache_timeout, cache_alias=cache_alias, key_prefix=key_prefix
)
Upvotes: 0
Views: 1340
Reputation: 599490
You're returning yet another decorator in the else clause. But at that point you need to be actually calling the decorated function and returning its result, as you do in the if clause.
(Note, the original decorator you post only has a single level of function and returns the decorator from that level, not from inside as you are trying to do.)
Edit You need to do the action of that decorator here: that is, check the cache, and either return the cached item or call the view.
To be honest, the easiest thing is to simply write that functionality directly. Stripped of all the logic the decorator and middleware do to make them generic, it's just:
key = get_cache_key(request, key_prefix=key_prefix, 'GET', cache=cache_alias)
response = cache.get(cache_key)
if response is None:
response = func(*fargs, **fkwargs)
cache.set(cache_key, response, cache_timeout)
return response
Upvotes: 4