Find the required permissions of Django URLs without calling them?

前端 未结 3 1169
忘了有多久
忘了有多久 2021-02-09 01:17

My Django app currently has URLs which are protected by \'permission_required()\' functions.

This function is called in three different ways.

  1. As a decorato
3条回答
  •  粉色の甜心
    2021-02-09 02:05

    Here is an example of how to solve your problem:

    First, Create a decorator wrapper to use instead of 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
    

    Then, use it to decorate your views:

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

    Then, add a tag to use for your menu items:

    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
    

    And finally, in your templates, when building the menu tree:

    N.B. I've not tested the last part with the tag, but I hope you got the idea. The magic thing here is to add the permissions to the view_func in the decorator, and then you can access this using resolve(path). I'm not sure how this will behave in terms of performance, but after all that's just an idea.

    EDIT: Just fixed a bug in the example..

提交回复
热议问题