制作自定义 django 视图装饰器时遇到问题(带 args)

Posted

技术标签:

【中文标题】制作自定义 django 视图装饰器时遇到问题(带 args)【英文标题】:Having trouble making a custom django view decorator (with args) 【发布时间】:2013-11-26 17:14:51 【问题描述】:

所以我已经阅读了所有类似的问题并复制了他们写的内容,但我仍然遇到问题。所以我想要这样的东西

# Yes, I know django has one but I want to make my own
@rate_limit(seconds=10) 
myview(request, somearg, *args, **kwargs):
    # Return a response
...

def rate_limit(seconds=10):    
    def decorator(view):            
        def wrapper(request, *args, **kwargs):
            # Do some stuff
            return view(request, *args, **kwargs)       
        return wrapper
    return decorator

当我运行它时,我得到了错误

decorator() got an unexpected keyword argument 'somearg'

所以我附加装饰器来接收 args 和 kwargs 并得到这个错误

# New decorator signature
def decorator(view, *args, **kwargs)

和错误

'function' object has no attribute 'status_code'

编辑: 所以解决方案是使用。谢谢Martijn Pieters

@rate_limit()

而不是

@rate_limit

【问题讨论】:

Hrm,这些错误似乎都没有意义。你确实想用functools.wraps()装饰wrapper()from functools import wraps,然后@wraps(view)装饰def wrapper(...) def decorator(view):改成def decorator(view, *args, **kwargs): @karthikr:这不是问题。不可能,因为装饰器被传递只是函数到装饰。我强烈怀疑这不是 OP 运行的完整代码。 @karthikr:那是在解决错误的问题。我怀疑 OP 没有调用装饰器工厂@rate_limit@rate_limit(10). @karthikr:不,你不能。它是rate_limit() 是一个装饰器factory。它产生装饰器。 decorator() 是这里的实际装饰器。 【参考方案1】:

您的第一次尝试效果很好,但您可能忘记调用rate_limit() 装饰器工厂。

换句话说,如果你这样做,你的第一个错误就会发生:

@rate_limit
def myview(request, somearg, *args, **kwargs):

代替:

@rate_limit(seconds=10)
def myview(request, somearg, *args, **kwargs):

您还真的想在 Django 中使用的装饰器上使用 functools.wraps(),特别是如果您想将它与其他 Django 装饰器(例如 csrf_exempt)混合使用:

from functools import wraps

def rate_limit(seconds=10):
    def decorator(view):
        @wraps(view)
        def wrapper(request, *args, **kwargs):
            # Do some stuff
            return view(request, *args, **kwargs)
        return wrapper
    return decorator

这可确保将要包装的函数上设置的任何属性正确复制到包装器。

【讨论】:

这成功了!我的意思是,在将 args 和 kwargs 添加到装饰器之后,将 () 添加到我的装饰器。为什么我必须像 @rate_limit() 那样调用它,而不是像其他装饰器那样调用 @rate_limit?或者如果需要参数,括号是否总是需要的? @JaredJoke: rate_limit() 是一个装饰器工厂。它生成实际的装饰器(它返回decorator),让您根据参数构建不同的装饰器。 rate_limit(10) 返回一个装饰器,rate_limit(20) 返回另一个。 Python 然后使用返回的decorator 来实际装饰myview() 视图函数。 @JaredJoke: @some_expression 真的只是意味着:执行some_expression,然后获取结果(必须是可调用的),并使用装饰函数调用它。所以rate_limit(10)返回decorator,称为传入myview,而decorator又返回wrapper(),替换myview函数。 django 如何让@login_required@login_required() 工作?...

以上是关于制作自定义 django 视图装饰器时遇到问题(带 args)的主要内容,如果未能解决你的问题,请参考以下文章

无效!有装饰器时不运行单元测试

用于重定向的 Django 自定义装饰器

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

Django - 自定义装饰器 - 参数未填充

关于路径和自定义装饰器的 Python3 Django 问题

Django学习笔记第八篇--实战练习四--为你的视图函数自定义装饰器