找不到Django URL所需的权限而不调用它们?

fad*_*bee 7 django authorization menu

我的Django应用程序目前拥有受'permission_required()'函数保护的URL.

该功能以三种不同的方式调用.

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

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

有没有办法在请求URL的情况下查询URL所需的权限?

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

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

Tis*_*sho 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
Run Code Online (Sandbox Code Playgroud)

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

@require_perms('my_perm',)
def home(request):
.....
Run Code Online (Sandbox Code Playgroud)

然后,添加一个用于菜单项的标签:

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
Run Code Online (Sandbox Code Playgroud)

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

<button href="{{ some_path }} {% if not check_menu_permissions some_path request.user %}disabled="disabled"{% endif %} />
Run Code Online (Sandbox Code Playgroud)

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

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