diff --git a/django/core/urlresolvers.py b/django/core/urlresolvers.py
index 34bca8a..c4d4420 100644
a
|
b
|
class RegexURLResolver(object):
|
303 | 303 | return self._resolve_special('500') |
304 | 304 | |
305 | 305 | def reverse(self, lookup_view, *args, **kwargs): |
| 306 | return self.reverse_with_prefix(lookup_view, '', *args, **kwargs) |
| 307 | |
| 308 | def reverse_with_prefix(self, lookup_view, _prefix, *args, **kwargs): |
306 | 309 | if args and kwargs: |
307 | 310 | raise ValueError("Don't mix *args and **kwargs in call to reverse()!") |
308 | 311 | try: |
… |
… |
class RegexURLResolver(object):
|
310 | 313 | except (ImportError, AttributeError), e: |
311 | 314 | raise NoReverseMatch("Error importing '%s': %s." % (lookup_view, e)) |
312 | 315 | possibilities = self.reverse_dict.getlist(lookup_view) |
| 316 | prefix_norm, prefix_args = normalize(_prefix)[0] |
313 | 317 | for possibility, pattern in possibilities: |
314 | 318 | for result, params in possibility: |
315 | 319 | if args: |
316 | | if len(args) != len(params): |
| 320 | if len(args) != len(params) + len(prefix_args): |
317 | 321 | continue |
318 | 322 | unicode_args = [force_unicode(val) for val in args] |
319 | | candidate = result % dict(zip(params, unicode_args)) |
| 323 | candidate = (prefix_norm + result) % dict(zip(params, unicode_args)) |
320 | 324 | else: |
321 | | if set(kwargs.keys()) != set(params): |
| 325 | if set(kwargs.keys()) != (set(params)|set(prefix_args)): |
322 | 326 | continue |
323 | 327 | unicode_kwargs = dict([(k, force_unicode(v)) for (k, v) in kwargs.items()]) |
324 | | candidate = result % unicode_kwargs |
325 | | if re.search(u'^%s' % pattern, candidate, re.UNICODE): |
| 328 | candidate = (prefix_norm + result) % unicode_kwargs |
| 329 | if re.search(u'^%s%s' % (_prefix, pattern), candidate, re.UNICODE): |
326 | 330 | return candidate |
327 | 331 | # lookup_view can be URL label, or dotted path, or callable, Any of |
328 | 332 | # these can be passed in at the top, but callables are not friendly in |
… |
… |
def reverse(viewname, urlconf=None, args=None, kwargs=None, prefix=None, current
|
386 | 390 | raise NoReverseMatch("%s is not a registered namespace inside '%s'" % (key, ':'.join(resolved_path))) |
387 | 391 | else: |
388 | 392 | raise NoReverseMatch("%s is not a registered namespace" % key) |
389 | | |
390 | | return iri_to_uri(u'%s%s' % (prefix, resolver.reverse(view, |
391 | | *args, **kwargs))) |
| 393 | return iri_to_uri(resolver.reverse_with_prefix(view, prefix, *args, **kwargs)) |
392 | 394 | |
393 | 395 | reverse_lazy = lazy(reverse, str) |
394 | 396 | |
diff --git a/tests/regressiontests/urlpatterns_reverse/namespace_urls.py b/tests/regressiontests/urlpatterns_reverse/namespace_urls.py
index 3d34049..0544e75 100644
a
|
b
|
urlpatterns = patterns('regressiontests.urlpatterns_reverse.views',
|
37 | 37 | (r'^default/', include(default_testobj.urls)), |
38 | 38 | |
39 | 39 | (r'^other1/', include(otherobj1.urls)), |
40 | | (r'^other2/', include(otherobj2.urls)), |
| 40 | (r'^other[246]/', include(otherobj2.urls)), |
41 | 41 | |
42 | | (r'^ns-included1/', include('regressiontests.urlpatterns_reverse.included_namespace_urls', namespace='inc-ns1')), |
| 42 | (r'^ns-included[135]/', include('regressiontests.urlpatterns_reverse.included_namespace_urls', namespace='inc-ns1')), |
43 | 43 | (r'^ns-included2/', include('regressiontests.urlpatterns_reverse.included_namespace_urls', namespace='inc-ns2')), |
44 | 44 | |
45 | 45 | (r'^included/', include('regressiontests.urlpatterns_reverse.included_namespace_urls')), |
| 46 | (r'^inc(?P<outer>\d+)/', include('regressiontests.urlpatterns_reverse.included_urls', namespace='inc-ns5')), |
46 | 47 | |
47 | 48 | ) |
diff --git a/tests/regressiontests/urlpatterns_reverse/tests.py b/tests/regressiontests/urlpatterns_reverse/tests.py
index 4f391d9..71e1913 100644
a
|
b
|
resolve_test_data = (
|
49 | 49 | # Nested namespaces |
50 | 50 | ('/ns-included1/test3/inner/42/37/', 'urlobject-view', 'testapp', 'inc-ns1:test-ns3', 'empty_view', tuple(), {'arg1': '42', 'arg2': '37'}), |
51 | 51 | ('/ns-included1/ns-included4/ns-included2/test3/inner/42/37/', 'urlobject-view', 'testapp', 'inc-ns1:inc-ns4:inc-ns2:test-ns3', 'empty_view', tuple(), {'arg1': '42', 'arg2': '37'}), |
| 52 | |
| 53 | # Namespaces capturing variables |
| 54 | ('/inc70/', 'inner-nothing', None, 'inc-ns5', views.empty_view, tuple(), {'outer': '70'}), |
| 55 | ('/inc78/extra/foobar/', 'inner-extra', None, 'inc-ns5', views.empty_view, tuple(), {'outer':'78', 'extra':'foobar'}), |
| 56 | |
52 | 57 | ) |
53 | 58 | |
54 | 59 | test_data = ( |
… |
… |
class NamespaceTests(TestCase):
|
335 | 340 | self.assertEqual('/ns-included1/ns-included4/ns-included1/test3/inner/37/42/', reverse('inc-ns1:inc-ns4:inc-ns1:test-ns3:urlobject-view', args=[37,42])) |
336 | 341 | self.assertEqual('/ns-included1/ns-included4/ns-included1/test3/inner/42/37/', reverse('inc-ns1:inc-ns4:inc-ns1:test-ns3:urlobject-view', kwargs={'arg1':42, 'arg2':37})) |
337 | 342 | |
| 343 | def test_nested_namespace_with_variable(self): |
| 344 | self.assertEqual('/inc54/', reverse('inc-ns5:inner-nothing', kwargs={'outer':'54'})) |
| 345 | self.assertEqual('/inc78/extra/foobar/', reverse('inc-ns5:inner-extra', kwargs={'outer':'78', 'extra':'foobar'})) |
| 346 | |
338 | 347 | def test_app_lookup_object(self): |
339 | 348 | "A default application namespace can be used for lookup" |
340 | 349 | self.assertEqual('/default/inner/', reverse('testapp:urlobject-view')) |