Django自定义装饰器 - 函数没有属性get

时间:2017-12-06 17:21:50

标签: python django django-views decorator python-decorators

我试图基于@cache_page装饰器创建自己的装饰器。我的装饰器应该与@cache_page完全相同,除非视图的slug属性与request.user.userprofile slug匹配,然后通常处理视图并返回未缓存的响应

伪代码:

def profile(request,slug):
    # if not request.user = User.objects.get(userprofile__slug=slug): 
    # return cache
    # else compute response and return it

我的装饰者:

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

如果用户匹配slug,则此方法有效。否则,它会提出:

  

例外值:
  '功能'对象没有属性' get'

完整追溯:

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'

你知道问题出在哪里吗?最好的方法是分别为用户和其他用户进行缓存。这个视图有2个缓存。

编辑:这是原始的@cache_page装饰器

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
    )

1 个答案:

答案 0 :(得分:4)

你要在else子句中返回另一个装饰器。但是在这一点上,你需要实际调用修饰函数并返回其结果,就像在if子句中那样。

(注意,您发布的原始装饰器只有一个级别的函数,并从该级别返回装饰器,而不是从您尝试的内部返回。)

编辑您需要在此处执行该装饰器的操作:即检查缓存,并返回缓存的项目或调用视图。

老实说,最简单的事情就是直接编写该功能。剥离装饰器和中间件所做的所有逻辑以使它们成为通用的,它只是:

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