Reputation: 5914
I am using django 1.7
and the module django-role-permissions
.
In my login/urls.py
:
from django.conf.urls import patterns, url
from . import views
urlpatterns = patterns('',
url(r'^$', views.login),
url(r'^logout$', views.logout),
url(r'^create_user$', views.create_user),
)
and in login/views.py
:
@has_role_decorator('EbagManager')
def create_user(request):
return HttpResponse('OK')
I've got in one in my templates link to create_user
: <a href="{% url 'login.views.create_user' %}">Create User</a>
Then I've got Django Exception:
NoReverseMatch at /core/index
Reverse for 'login.views.create_user' with arguments '()' and keyword arguments '{}' not found. 0 pattern(s) tried: []
However when I remove @has_role_decorator('EbagManager')
there is no problem with that url and successfully loaded it. What is going on?
This is the code of the decorator:
def has_role_decorator(role):
def request_decorator(dispatch):
def wrapper(request, *args, **kwargs):
user = request.user
if user.is_authenticated():
if has_role(user, role):
return dispatch(request, *args, **kwargs)
raise PermissionDenied
return wrapper
return request_decorator
and it seems perfectly fine to me. Why does this decorator break reverse
?
Upvotes: 0
Views: 327
Reputation: 1121486
You'll need to copy across the name of the wrapped function (referenced by dispatch
) to your wrapper
function. This is easiest done with the @functools.wraps()
decorator factory:
from functools import wraps
def has_role_decorator(role):
def request_decorator(dispatch):
@wraps(dispatch)
def wrapper(request, *args, **kwargs):
user = request.user
if user.is_authenticated():
if has_role(user, role):
return dispatch(request, *args, **kwargs)
raise PermissionDenied
return wrapper
return request_decorator
Without using @functools.wraps()
, create_user.__name__
is set to 'wrapper'
, and the create_user.__module__
attribute would name the module where you defined the decorator, meaning that to reverse the view you'd have to use decorator_module.wrapper
as the lookup. Any view using the decorator would be registered under that name however.
Upvotes: 2
Reputation: 599490
You can solve this without changing the decorator by giving your URL a specific name
attribute, and use that in reverse:
url(r'^create_user$', views.create_user, name='create_user'),
Upvotes: 1