【问题标题】:Multiple decorators for a view in Django: Execution orderDjango中视图的多个装饰器:执行顺序
【发布时间】:2012-02-01 16:36:22
【问题描述】:

我正在尝试用两个装饰器来装饰 Django 视图,一个用于检查登录,一个用于检查 is_active。

第一个是内置的@login_required,第二个如下:

def active_required(function):
    dec = user_passes_test(lambda u: u.is_active, '/notallowed', '')
    return dec(function)

现在,Python 中的装饰器由内而外地工作,但以下内容不起作用:

@active_required
@login_required
def foo(request):
    ...

我想先检查用户是否登录,如果没有,则重定向到登录页面,如果他或她登录,我想检查他或她是否处于活动状态,如果没有,则执行重定向到'/notallowed'

如果login_required失败了,用户并没有被重定向到登录页面,而是@active_required被执行了,由于这种情况下用户为null,@active_required装饰器失败,用户被重定向到@ 987654326@.

更改顺序似乎有效,

@login_required
@active_required
def foo(request):
    ...

但我怀疑这种方法也有问题。

组合两个装饰器的正确方法是什么,为什么执行顺序与简单的 Python 装饰器不同?

【问题讨论】:

    标签: python django decorator


    【解决方案1】:

    现在,Python 中的装饰器是由内而外工作的

    嗯,我想这取决于你对由内而外的定义。在您的情况下,您希望 @login_required 首先执行,因此它应该是“最外层”(顶部)装饰器。

    正如您所指出的,您的最后一个示例有效,并且确实是执行此操作的正确方法。

    编辑

    困惑可能在于这些特定的装饰器是如何工作的。

    @login_required(@original_view) 返回一个新视图,它首先检查你是否登录,然后调用 original_view

    所以

    
        @login_required(
            @active_required(
                @my_view
            )
        )
    
    first checks if you are logged in, then
        first(second) checks if you are active, then
            runs my_view
    

    【讨论】:

    【解决方案2】:

    装饰器按照它们在源代码中出现的顺序应用。因此,您的第二个示例:

    @login_required
    @active_required
    def foo(request):
        ...
    

    等价于:

    def foo(request):
        ...
    foo = login_required(active_required(foo))
    

    因此,如果一个装饰器的代码依赖于另一个装饰器设置(或确保)的东西,则必须将依赖的装饰器放在依赖的装饰器“内部”。

    但是,正如 Chris Pratt 所说,您应该避免使用装饰器依赖项;必要时,创建一个新的装饰器,以正确的顺序调用两者。

    【讨论】:

    • 好的,但我想要反过来:首先,应该应用 login_required,然后是 active_required。那么,不应该像我给出的第一个例子那样吗?
    • 在这种情况下,首先应用login_required——一种思路是,对foo的调用先经过login_required返回的函数,再经过返回的函数通过active_required。您可以使用 PDB 单步执行,或添加调试 prints 以了解我的意思。
    【解决方案3】:

    只有当装饰器具有真正独特的功能时,堆叠装饰器才真正有意义。根据您的描述,永远不会出现您想要使用active_required login_required 的情况。因此,拥有一个 login_and_active_required 装饰器来检查两者并相应地分支会更有意义。少打字,少记录,解决问题。

    【讨论】:

    • 好吧,我认为 Django 内置函数会比自定义代码更可靠。 Django 没有这个装饰器有点奇怪,不过,它应该很常见。我看到了一些标记为 WONTFIX 的错误报告。
    • 同意。由于is_active 是内置的,并且在大多数情况下几乎否定了login_required,因此开发人员应该开箱即用地考虑到这一点,但只能看到。
    【解决方案4】:

    再解释一下(起初我也很困惑):首先应用active_required,因为它需要my_view并将其包装在一些代码中。然后应用login_required 并将结果包装在更多代码中。

    但是当实际调用my_view 的这个包装版本时,首先执行login_required 添加的代码(检查您是否已登录),然后执行active_required 添加的代码(检查您'reactive) 然后最后my_view 被执行。

    【讨论】:

    猜你喜欢
    • 2015-02-05
    • 1970-01-01
    • 2018-10-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-03-28
    • 1970-01-01
    • 2012-08-02
    相关资源
    最近更新 更多