有条件地在Django中应用login_required装饰器

时间:2017-03-28 09:06:03

标签: python django decorator

我在views.py中有一组功能,目前只有用户可以访问。我被要求公开访问,目前我在视图中使用@login_required装饰器。有没有办法根据所服务的对象有条件地应用这个装饰器?

例如,我views.py的一部分:

@login_required
def details(request, object_id):
    o = get_object_or_404(Model, pk=object_id)

    if o.user_id == request.user.pk:
        return render(request, 'app/details.html')
    else:
        return redirect('app:home')

我想做什么:

if not o.is_public:
    @login_required
def details(request, object_id):
    o = get_object_or_404(Model, pk=object_id)

    if o.user_id == request.user.pk:
        return render(request, 'app/details.html')
    else:
        return redirect('app:home')

当然,代码不起作用,因为(i)它不是有效的Python和(ii)我需要先得到对象。我相信使用Django可能会有一个优雅的解决方案,因为这在Web应用程序中是一个非常常见的功能,但我已经通过文档无济于事。我想我应该用另一个装饰器包围@login_required装饰器,但我不太熟悉Python中的装饰器。任何帮助表示赞赏。

2 个答案:

答案 0 :(得分:0)

您可以使用user_passes_test来表达此类行为。

from django.contrib.auth.decorators import user_passes_test

def public_check(user):
    if user.is_public:
        return True

@user_passes_test(public_check)

答案 1 :(得分:0)

它不适用于装饰器,因为装饰器在导入时被评估并应用,正如您所说,您需要首先获取对象,这取决于请求。

由于您已经要求一个优雅的解决方案,并且我假设您想为它创建一个装饰器,以便您可以在多个视图上重复使用它,那么解决方案就是基于类的视图。您可以将您想要的行为实现为基于类的视图mixin,您可以将其混合到不同的基于类的视图中。这种改进的灵活性是引入基于类的视图的原因之一。