应用装饰器进行查看 - 反向找不到网址

时间:2015-01-31 12:11:09

标签: python django decorator python-decorators

我正在使用django 1.7和模块django-role-permissions

在我的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),
)

login/views.py

@has_role_decorator('EbagManager')
def create_user(request):
    return HttpResponse('OK')

我的模板中有一个链接到create_user<a href="{% url 'login.views.create_user' %}">Create User</a>

然后我得到了Django异常:

NoReverseMatch at /core/index
Reverse for 'login.views.create_user' with arguments '()' and keyword arguments '{}' not found. 0 pattern(s) tried: []

但是当我删除@has_role_decorator('EbagManager')时,该网址没有问题并成功加载它。到底是怎么回事? 这是装饰者的代码:

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

对我来说似乎完全没问题。为什么这个装饰器会中断reverse

2 个答案:

答案 0 :(得分:2)

您需要将包装函数的名称(由dispatch引用)复制到wrapper函数。使用@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

不使用@functools.wraps()create_user.__name__设置为'wrapper'create_user.__module__属性会命名您定义装饰器的模块,这意味着要反转视图必须使用decorator_module.wrapper作为查找。但是,使用装饰器的任何视图都将以该名称注册。

答案 1 :(得分:1)

您可以在不更改装饰器的情况下解决此问题,方法是为您的网址指定一个特定的name属性,并反过来使用它:

url(r'^create_user$', views.create_user, name='create_user'),