Django从内部装饰器

时间:2015-12-30 17:54:10

标签: python django redirect python-decorators

我一直在努力让Django的URL重定向在装饰器内部工作。考虑这个简单的装饰器,确保视图的id参数为奇数:

from django.conf import settings
from django.conf.urls import url
from django.shortcuts import redirect
from django.http import HttpResponse
from django.core.urlresolvers import reverse
from django.utils.decorators import available_attrs

from functools import wraps

def ensure_odd_id(view):
    @wraps(view, assigned=available_attrs(view))
    def inner(request, *args, **kwargs):
        id = int(kwargs.get('id'))

        if id % 2 == 0:
            d = kwargs.copy()
            d['id'] = str(id + 1)

            return redirect(reverse(view, args=args, kwargs=d))

        return view(request, *args, **kwargs)
    return inner

@ensure_odd_id
def test(request, id):
    return HttpResponse('test {}'.format(id))

urlpatterns = [url(r'^test/(?P<id>\d+)/$', test)]

if __name__ == '__main__':
    settings.configure(DEBUG=True, ROOT_URLCONF='test')

    from django.core.management import execute_from_command_line
    execute_from_command_line()

如果您将此脚本保存为test.py并使用python test.py runserver运行,则会看到请求/test/13不会产生错误,但请求/test/18会产生{{1}调用NoReverseMatch时出错,而不是重定向到reverse

/test/19

我觉得这与NoReverseMatch at /test/18/ Reverse for 'test.test' with arguments '()' and keyword arguments '{'id': '19'}' not found. 0 pattern(s) tried: [] 函数是未装饰的view这一事实有关,而URL解析器只处理装饰视图。

有没有很好的方法可以在没有黑客内省的情况下重定向到装饰的view本身?

1 个答案:

答案 0 :(得分:0)

Django实际上在reverse中使用了视图函数本身,所以我只需要传递装饰函数而不是原始视图:

return redirect(reverse(inner, args=args, kwargs=d))
                        ^^^^^