8

我的 Django 应用程序当前具有受“permission_required()”函数保护的 URL。

该函数以三种不同的方式调用。

  1. 作为views.py 中的装饰器,带有硬编码的参数。
  2. 作为一个普通函数,具有自动生成的参数,在自定义基于类的通用视图中。
  3. 作为在 urls.py 中调用视图的函数,带有硬编码参数。

我现在正在向应用程序添加一个菜单系统,我需要让菜单条目反映用户是否有权请求每个菜单条目的 URL。(通过灰显或隐藏所述条目。)

有没有一种方法可以在不请求URL 的情况下查询 URL 所需的权限?

到目前为止,我想到的唯一解决方案是用无参数的“menu_permssion_required()”装饰器替换装饰器,并将所有权限硬编码到 Python 结构中。这似乎是倒退了一步,因为我的自定义基于类的通用视图已经自动生成了它们所需的权限。

有关如何制作反映当前用户 URL 权限的菜单系统的任何建议?

4

3 回答 3

2

有没有一种方法可以在不请求 URL 的情况下查询 URL 所需的权限?

User.has_perm()User.has_module_perms()

有关如何制作反映当前用户 URL 权限的菜单系统的任何建议?

我真的很喜欢这个问题,因为它涉及使用 django 制作网站的任何人,所以我觉得它非常相关。我自己也经历过,甚至在 2008 年的第一个 django 项目中编写了一个菜单“系统”。但从那以后我尝试了 Pinax,我从他们的示例项目中学到的(这么多)东西之一是完全不必要的膨胀。

所以,我没有建议我会支持如何制作一个尊重请求用户权限的菜单“系统”。

我确实有一个关于如何制作一个尊重请求用户权限的简单菜单的建议,所以这可能不是完全无关的。

  1. 只需用纯 HTML 制作您的菜单,它不会经常更改以至于必须生成它。这也将使您的 Python 代码更简单。

  2. 添加到settings.TEMPLATE_CONTEXT_PROCESSORS'django.core.context_processors.PermWrapper'

  3. 使用{{ perms }} proxy到 User.has_perms。

例子:

{% if perms.auth %}
    <li class="divider"></li>

    {% if perms.auth.change_user %} 
    <li>
        <a href="{% url admin:auth_user_changelist %}">{% trans 'Users' %}</a>
    </li>
    {% endif %} 

    {% if perms.auth.change_group %} 
    <li>
        <a href="{% url admin:auth_group_changelist %}">{% trans 'User groups' %}</a>
    </li>
    {% endif %} 

{% endif %} 
{# etc, etc #}

这就是我保持导航简单愚蠢不碍事的方式。但我也总是在离菜单不远的地方包含一个自动完成功能,以允许用户轻松导航到任何详细信息页面。所以,这就是我对 django 项目中导航的了解,我很想阅读其他答案!

于 2012-06-10T19:15:07.300 回答
2

以下是如何解决您的问题的示例:

首先,创建一个装饰器包装器来代替permission_required:

from django.contrib.auth.decorators import login_required, permission_required, user_passes_test
from django.core.exceptions import PermissionDenied
from functools import wraps
from  django.utils.decorators import available_attrs

def require_perms(*perms):
    def decorator(view_func):
        view_func.permissions = perms
        @wraps(view_func, assigned=available_attrs(view_func))
        def _wrapped_view(request, *args, **kwargs):
            for perm in perms:
                return view_func(request, *args, **kwargs)
            raise PermissionDenied()
        return _wrapped_view
    return decorator

然后,用它来装饰你的视图:

@require_perms('my_perm',)
def home(request):
.....

然后,为您的菜单项添加一个标签:

from django.core.urlresolvers import resolve

def check_menu_permissions(menu_path, user):
    view = resolve(menu_path)
    if hasattr(view.func, "permissions"):
        permissions = view.func.permissions
        for perm in permissions:
            if user.has_perm(perm):
                return True # Yep, the user can access this url
            else:
                return False # Nope, the user cannot access this url
    return True #  or False - depending on what is the default behavior

最后,在您的模板中,在构建菜单树时:

<button href="{{ some_path }} {% if not check_menu_permissions some_path request.user %}disabled="disabled"{% endif %} />

注意我没有用标签测试最后一部分,但我希望你明白了。这里的神奇之处在于在装饰器中为 view_func 添加权限,然后您可以使用 resolve(path) 访问它。我不确定这在性能方面的表现如何,但毕竟这只是一个想法。

编辑:刚刚修复了示例中的错误..

于 2012-06-10T19:59:59.183 回答
1

我有一个类似的问题,但它更深入一点。除了权限之外,我还想要基于隐藏在用户中的其他测试(即is_staff,或user.units.count() > 1)。在视图和模板中复制这些似乎容易出错。

您可以内省视图对象,并查看包装它的所有装饰器,并确定它们是否是检查(在我的情况下:第一个参数 Iduuser)。如果它们都通过,则允许呈现链接。

获取包装函数的所有装饰器更详细地描述了该技术。{% url %}您可以在Django-menus找到将其包装成方便替代品的应用程序。

于 2012-06-11T11:46:31.517 回答