在Django模板中:检查用户是否有权限访问指定名称的视图

3

假设我有一个视图,已经使用user_passes_test装饰器进行了修饰:

# myapp/views.py
from django.views.generic import TemplateView
from django.contrib.auth.decorators import user_passes_test

def has_perm1_or_perm2(user):
    return user.has_perm('myapp.perm1') or user.has_perm('myapp.perm2')

@user_passes_test(has_perm1_or_perm2)
class MyView(TemplateView):
    # my view code goes here

我将其与URL连接起来,方法如下:

# myapp/urls.py
from django.conf.urls import url
from . import views

urlpatterns = [
    ...,
    url(r'^myview$', views.MyView.as_view(), name='myview'),
    ...
]

如果我想在模板中添加到此视图的链接,代码如下所示:

{% url 'view_name' %}

。此处的“view_name”是视图函数的名称。
<a href="{% url 'myapp:myview' %}">Check out my view!</a>

但我希望能够在模板中加入一些控制,使得上述内容仅在当前登录用户被指定视图的user_passes_test函数所批准时才显示。

也就是说,我希望我的模板看起来像这样:

{% if check_user_has_view_permission request.user 'myapp:myview' %}
<a href="{% url 'myapp:myview' %}">Check out my view!</a>
{% else %}
Nothing to see here...
{% endif %}

我该如何实现这一点?

谢谢!


装饰器在我所知道的情况下不起作用。在Django 1.9之前,您必须编写自己的mixin或装饰视图的“dispatch”方法。 - solarissmoke
我认为文档表明类装饰器方法可行(只要你将装饰器包装在' method_decorator '函数内):https://docs.djangoproject.com/es/1.9/topics/class-based-views/intro/#decorating-the-class - 8one6
从您引用的链接中: "要装饰类视图的每个实例,您需要装饰类定义本身。 为此,您将装饰器应用于类的dispatch()方法。" - solarissmoke
或者在同一页的第二段,更简洁地说,您可以装饰类并将要装饰的方法名称作为关键字参数名称传递: - 8one6
是的,你说得对!但是你随后使用了method_decorator函数并传递了一个name参数。也就是说,你不能直接用user_passes_test修饰类。 - solarissmoke
显示剩余2条评论
1个回答

2
你可以编写一个自定义模板过滤器(custom template filter)来实现此功能:
# myapp/templatetags/my_app_tags.py (probably need a better name...)
from django import template
from myapp.views import has_perm1_or_perm2

register = template.Library()

@register.filter
user_has_special_perms(user):
    return has_perm1_or_perm2(user)

然后在你的模板中:

{% load my_app_tags %}

{% if request.user|user_has_special_perms %}
<a href="{% url 'myapp:myview' %}">Check out my view!</a>
{% else %}
Nothing to see here...
{% endif %}

或者,您可以直接检查每个权限,如下所示:

{% if perms.myapp.perm1 and perms.myapp.perm2 %}

(显然这不够DRY)。

编辑 - 如何使其更通用?

为了使其更通用,你可以像这样做。首先创建一些视图到权限的映射,例如:

# myapp/views.py
VIEW_PERMISSIONS = {
    'MyView': has_perm1_or_perm2,
    # etc for other views
}

然后像这样修改模板过滤器:
from myapp.views import VIEW_PERMISSIONS

@register.filter
user_has_special_perms(user, view_class):
    perm_func = VIEW_PERMISSIONS.get(view_class, None)
    if perm_func is not None:
        return perm_func(user)
    return false

然后在模板中:

{% if request.user|user_has_special_perms:"MyView" %}

我相信可以通过查看视图类本身的某种内省方式,在不需要通过VIEW_PERMISSIONS进行显式映射的情况下实现此操作。


这是一个合理的开端,但在当前的呈现方式中它并不像我想要的那样通用。特别是,在我的实际应用程序中,我将拥有数十个视图函数,每个函数都将有一个(可能是)独特的用户授权检查函数。(视图1可能是 perma 或 permb...视图2可能是 perma 和 permc等)。因此,解决方案必须不需要手动生成每个用户权限检查函数的过滤器,标签需要根据其URL名称自动确定哪个函数适用于给定的视图。这可行吗? - 8one6
我已经编辑了答案,给出了一种可能的方法来使其更加通用。理想情况下,您需要对类本身进行一些内省。 - solarissmoke
我正在仔细阅读这个答案(https://dev59.com/PmTWa4cB1Zd3GeqPG8wp),看看是否可以利用那种方法。特别是,作者似乎建议使用核心权限检查装饰器的升级版本。在装饰发生之前,它会将验证函数本身作为属性附加到视图函数上。这应该使得以后可以重新调用验证函数。 - 8one6

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接