Django中视图的多个装饰器:执行顺序

ust*_*tun 32 python django decorator

我试图通过两个装饰器来装饰Django视图,一个用于检查登录,另一个用于检查is_active.

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

def active_required(function):
    dec = user_passes_test(lambda u: u.is_active, '/notallowed', '')
    return dec(function)
Run Code Online (Sandbox Code Playgroud)

现在,Python中的装饰器内部工作,但以下不起作用:

@active_required
@login_required
def foo(request):
    ...
Run Code Online (Sandbox Code Playgroud)

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

如果login_required失败,用户不会被重定向到登录页面,而是@active_required被执行,并且由于用户在这种情况下为空,@ active_required装饰器失败并且用户被重定向到/notallowed.

改变顺序似乎有效,

@login_required
@active_required
def foo(request):
    ...
Run Code Online (Sandbox Code Playgroud)

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

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

sec*_*ond 32

现在,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_vew
Run Code Online (Sandbox Code Playgroud)

  • 嗯,我仍然对订单感到有些困惑:http://stackoverflow.com/a/739665/72436和http://stackoverflow.com/a/8715839/72436否则建议. (2认同)

dcr*_*sta 15

装饰器按它们在源中出现的顺序应用.因此,你的第二个例子:

@login_required
@active_required
def foo(request):
    ...
Run Code Online (Sandbox Code Playgroud)

相当于以下内容:

def foo(request):
    ...
foo = login_required(active_required(foo))
Run Code Online (Sandbox Code Playgroud)

因此,如果一个装饰器的代码依赖于由另一个装饰器设置(或由另一个装饰器确定),则必须将依赖装饰器"置于"depdended-on装饰器内部.

但是,正如Chris Pratt所说,你应该避免使用装饰器依赖; 必要时,创建一个新的装饰器,以正确的顺序调用它们.


Chr*_*att 12

如果装饰器具有真正独特的功能,那么它们才真正有意义.根据您的描述,您永远不会想要使用active_required不会 使用login_required.因此,让login_and_active_required装饰器相应地检查两者和分支更有意义.少输入,少记录,否定问题.


Den*_*zov 5

为了进一步解释它(我一开始也感到困惑):active_required首先应用它是指它将它my_view封装在一些代码中。然后login_required应用,并将结果包装在更多代码中。

但是,当my_view实际调用此包装版本时,首先login_required执行by添加的代码(检查您是否已登录),然后active_required执行by by添加的代码(检查您是否处于活动状态),最后my_view执行。