在Django中有多个装饰器并且只使用一个

在Django中有多个装饰器并且只使用一个,django,decorator,django-authentication,Django,Decorator,Django Authentication,我使用允许对使用Django作为后端的Android项目进行身份验证。该项目还有一个web界面 django tokenapi使用@token\u required装饰器来保护某些视图。Django使用@login\u required装饰程序来保护某些视图 我希望只有一个视图受@login\u required或@token\u required保护,因此它可以与webapp或Android应用程序一起使用 因此,理想情况下,它看起来是这样的: @token_required @login_r

我使用允许对使用Django作为后端的Android项目进行身份验证。该项目还有一个web界面

django tokenapi使用
@token\u required
装饰器来保护某些视图。Django使用
@login\u required
装饰程序来保护某些视图

我希望只有一个视图受
@login\u required
@token\u required
保护,因此它可以与webapp或Android应用程序一起使用

因此,理想情况下,它看起来是这样的:

@token_required
@login_required
def names_update(request):
    ....
    ....

然而,这是行不通的。有没有更好的方法?或者,正确的做法是拥有两个视图,一个是webapp,另一个是Android,这两个视图都受到适当的decorator的保护,然后使用相同的方法。

在一个视图上可以使用多个decorator。但是在这种情况下,我认为你应该把视图分开,把装饰师分开。否则,
token\u required
decorator将尝试使用在使用浏览器发出的请求中不可用的令牌进行身份验证。

您可以尝试将新视图变量分配给旧视图:

@token_required
def names_update_token(request):
    ...

@login_required
names_update_login = names_update_token
这应该具有创建名为names\u update\u login的第二个视图的效果,该视图只是指向第一个视图的指针,因此代码保持不变

编辑:

另一个想法,也是我曾经使用过的,是创建一个更“通用”的视图,并从其他每个视图调用它:

def update_token(request):
    ...

@token_required
def names_update_token(request):
    update_token(request)

@login_required
def names_update_login(request):
    update_token(request)

这解决了您提到的问题,同时仍然只保留实现视图的实际代码的一个副本。

不,如果可能的话,没有简单的方法根据您描述的编写通用的
装饰器

但是,您可以编写一个新的decorator,它完全满足您的需要:

from functools import wraps
from django.contrib.auth import authenticate, login
from django.views.decorators.csrf import csrf_exempt

def token_or_login_required(view_func):
    """
    Decorator which ensures the user is either logged in or
    has provided a correct user and token pair.
    """

    @csrf_exempt
    @wraps(view_func)
    def _wrapped_view(request, *args, **kwargs):
        user = request.REQUEST.get('user')
        if user and user.is_authenticated:
            return view_func(request, *args, **kwargs)

        token = request.REQUEST.get('token')

        if user and token:
            user = authenticate(pk=user, token=token)
            if user:
                login(request, user)
                return view_func(request, *args, **kwargs)
        return HttpResponseForbidden()
    return _wrapped_view

此装饰将和装饰器结合在一起,如果用户登录或令牌有效,则允许访问视图。

有趣的想法。当我尝试它时,它抛出了一个语法错误。我想装饰师希望在它之后有个活动。还有其他可能的方法吗?当遇到类似的情况时,我只是简单地从一个函数调用另一个函数。是的,这会起作用。但它需要为每个函数维护两个url.py设置。一个用于webapp,一个用于Android app。是的,不是很理想,但可以使用。有没有一种方法可以通过引用decorator代码而不是实际代码来做到这一点?@AlexisK我不知道你所说的引用是什么意思,但是你可以把这个代码放在任何地方,然后导入它,并把它作为任何其他装饰器使用。我的意思是,它是从另一个地方复制和粘贴代码。有没有办法避免复制和粘贴代码?这样,如果以后这些库中的内容发生了更改,则仍然会发生更改ok@AlexisK啊,我明白你的意思了。不幸的是,你不能和这些装饰师一起做。。考虑这种情况:当令牌或登录都未登录时,您希望运行哪个
else
?一个decorator将重定向,另一个将返回
HttpResponseForbidden()
ahh ok。谢谢你的回答。