Django 自定义装饰器 - 函数没有属性 get
Posted
技术标签:
【中文标题】Django 自定义装饰器 - 函数没有属性 get【英文标题】:Django custom decorator - function has no attribute get 【发布时间】:2018-05-20 16:10:48 【问题描述】:我正在尝试基于@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,这将有效。否则,它会引发:
异常值: 'function' 对象没有属性 '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
)
【问题讨论】:
如果我没记错的话,如果你不小心,装饰器有时会“隐藏”异常。我期望发生的是User.objects.get(...)
在你的装饰器中抛出一个异常并且装饰器返回失败的函数,这意味着它是一个函数对象,但该对象缺少它需要的get
。将装饰器的内部包裹在 try/except
中并打印出您的异常。可能会让您更准确地描述问题。
好的,我会试一试,但我认为这是因为我返回的 decorator_from_middleware_with_args 不会调用视图。
如果decorator_from_middleware_with_args
没有定义get
函数,那么你绝对正确,它可能来自那里。而且由于您要在装饰器中返回装饰器……是的,这可能是个问题。
【参考方案1】:
你在 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
【讨论】:
谢谢,不知道要返回什么。我不能只返回 func 因为我需要执行中间件。试过return CacheMiddleware(cache_timeout=cache_timeout, cache_alias=cache_alias, key_prefix=key_prefix).process_request(request) or func(*fargs, **fkwargs)
不会引发错误,但它也不会缓存任何东西。以上是关于Django 自定义装饰器 - 函数没有属性 get的主要内容,如果未能解决你的问题,请参考以下文章