Find the required permissions for Django URLs without calling them?

My Django app currently has URLs that are protected by allowed request () functions.

This function is called in three different ways.

  • Like a decorator in views.py, with hard-coded parameters.
  • As a simple function with an auto-generated parameter in custom general representations of the class.
  • As a function that calls views in urls.py, with hard-coded parameters.

Now I am adding a menu system to the application, and I need the menu items to show if the user has the right to request the URL of each entry in the menu. (Either by cutting or hiding the specified entries.)

Is there a way to request the permissions required for a URL without requesting a URL?

The only solution that I have been thinking about so far is to replace the decorator with the parametric "menu_permssion_required ()" decorator and hard code of all permissions into the Python structure. This seems like a step backwards, since my custom class-based Generic Views already automatically generate the required permissions.

Any suggestions on how to create a menu system that displays URL permissions for the current user?

+7
source share
3 answers

Here is an example of how to solve your problem:

First, create a decorator shell to use instead of resolved_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 the tag that will be used 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 creating the menu tree:

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

NB I have not tested the last part with the tag, but hope you have an idea. The magic here is to add permissions to the view_func in the decorator, and then you can access it with a permission (path). I'm not sure how this will behave in terms of performance, but this is just an idea.

EDIT : fixed bug in example.

+2
source

Is there a way to request the permissions required for a URL without requesting a URL?

User.has_perm () and User.has_module_perms ()

Any suggestions on how to create a menu system that displays URL permissions for the current user?

I really like this question because it applies to anyone who makes a site with django, so I find it really relevant. I went through this myself and even coded the "system" menu in my first django project back in 2008. But since then I have tried Pinax, and one of the (so many) things that I learned from their sample projects is that it is completely unnecessary bloat.

So, I have no suggestion that I would support, how to create a "system" menu that respects the user's permissions to the request.

I have a suggestion on how to create a simple menu that respects the permission of the user of the request, so that this may not be completely unrelated.

  • Just make your menu in plain HTML , it doesn't change that often that it needs to be generated. It will also simplify your Python code.

  • Add to settings.TEMPLATE_CONTEXT_PROCESSORS : 'django.core.context_processors.PermWrapper'

  • Use the {{ perms }} proxy for User.has_perms.

Example:

 {% 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 #} 

The way I continue navigating is simple , stupid and aloof . But also, I always turn on autocomplete next to the menu so that the user can easily go to any detailed page. So, all that I know about navigation in django projects, I want to read other answers!

+2
source

I had a similar problem, but it went a little deeper. Instead of just allowing, I also wanted other tests to be based on a sheet in the user (i.e. is_staff or user.units.count() > 1 ). Duplicate them in the view, and the pattern seems prone to errors.

You can inherit a view object and see how all the decorators wrap it, and work if they are checks (in my case: the first argument is u or user ). If all of them pass, give a link to the link.

Get all decorators wrapping a function describes the technique in a little more detail. You can find an application that portes this to a convenient replacement for {% url %} with Django-menus .

+1
source

All Articles