From 9be01a6e4d0d9fda1560b064aaafe217970c015b Mon Sep 17 00:00:00 2001 From: Carlton Gibson Date: Mon, 7 Apr 2014 19:51:37 +0200 Subject: [PATCH] Reverse order to checks in reverse. Add namespace then fallback to non-namespaced to allow reversing of non-namespaced views from namespaced request --- rest_framework/reverse.py | 32 +++++++++++++++++----------- rest_framework/tests/test_reverse.py | 7 ++++++ 2 files changed, 26 insertions(+), 13 deletions(-) diff --git a/rest_framework/reverse.py b/rest_framework/reverse.py index d4240533b..5d21d55c6 100644 --- a/rest_framework/reverse.py +++ b/rest_framework/reverse.py @@ -2,7 +2,7 @@ Provide reverse functions that return fully qualified URLs """ from __future__ import unicode_literals -from django.core.urlresolvers import reverse as django_reverse +from django.core.urlresolvers import reverse as django_reverse, NoReverseMatch from django.utils.functional import lazy from django.core.urlresolvers import resolve from django.http import Http404 @@ -18,21 +18,27 @@ def reverse(viewname, args=None, kwargs=None, request=None, format=None, **extra kwargs = kwargs or {} kwargs['format'] = format - if request: - try: - namespace = request.resolver_match.namespace - except AttributeError: + try: + viewname_to_try = viewname + if request: try: - namespace = resolve(request.path).namespace - except Http404: - namespace=None + namespace = request.resolver_match.namespace + except AttributeError: + try: + namespace = resolve(request.path).namespace + except Http404: + namespace=None - if namespace and ':' not in viewname: - viewname = '{namespace}:{viewname}'.format(namespace=namespace, - viewname=viewname) + if namespace and ':' not in viewname: + viewname_to_try = '{namespace}:{viewname}'.format(namespace=namespace, + viewname=viewname) + + url = django_reverse(viewname_to_try, args=args, kwargs=kwargs, + **extra) + except NoReverseMatch: + url = django_reverse(viewname, args=args, kwargs=kwargs, + **extra) - url = django_reverse(viewname, args=args, kwargs=kwargs, - **extra) if request: return request.build_absolute_uri(url) diff --git a/rest_framework/tests/test_reverse.py b/rest_framework/tests/test_reverse.py index 1bb7882cb..f63e4ff1e 100644 --- a/rest_framework/tests/test_reverse.py +++ b/rest_framework/tests/test_reverse.py @@ -13,6 +13,7 @@ def null_view(request): v0_urlpatterns = patterns('', url(r'^view$', null_view, name='view'), + url(r'^other-view', null_view, name="other-view"), ) v1_urlpatterns = patterns('', @@ -52,6 +53,12 @@ class ReverseTests(TestCase): url = reverse('view', request=request) self.assertEqual(url, 'http://testserver/v2/view') + def test_namespaced_request_to_non_namespaced_view_not_in_namespace(self): + request = factory.get('/v2/view') + url = reverse('other-view', request=request) + self.assertEqual(url, 'http://testserver/other-view') + + # Additional tests for #1143 # Covering cases mentioned # https://github.com/tomchristie/django-rest-framework/pull/1143#issuecomment-30031591