应用装饰器查看 - url 没有被反向找到

Applying decorator to view - url not being found by reverse

我正在使用 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')

我的模板中有一个 link 到 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') 时 url 没有问题并成功加载它。到底是怎么回事? 这是装饰器的代码:

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?

您需要将包装函数的名称(由 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__ 属性将命名您定义装饰器的模块,这意味着反转view 你必须使用 decorator_module.wrapper 作为查找。但是,任何使用装饰器的视图都将以该名称注册。

你可以在不改变装饰器的情况下解决这个问题,方法是给你的 URL 一个特定的 name 属性,然后反过来使用它:

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