Code

Ticket #17551: 17551.diff

File 17551.diff, 6.4 KB (added by gnosek, 2 years ago)
Line 
1commit ad80a813decc7809c7f8d7c0693ac3216f6ac655
2Author: Grzegorz Nosek <root@localdomain.pl>
3Date:   Sat Feb 4 18:13:52 2012 +0100
4
5    #17551
6
7diff --git a/django/core/urlresolvers.py b/django/core/urlresolvers.py
8index b634b56..4a8ec2d 100644
9--- a/django/core/urlresolvers.py
10+++ b/django/core/urlresolvers.py
11@@ -245,7 +245,7 @@ class RegexURLResolver(LocaleRegexProvider):
12                 p_pattern = p_pattern[1:]
13             if isinstance(pattern, RegexURLResolver):
14                 if pattern.namespace:
15-                    namespaces[pattern.namespace] = (p_pattern, pattern)
16+                    namespaces.setdefault(pattern.namespace, []).append((p_pattern, pattern))
17                     if pattern.app_name:
18                         apps.setdefault(pattern.app_name, []).append(pattern.namespace)
19                 else:
20@@ -256,8 +256,9 @@ class RegexURLResolver(LocaleRegexProvider):
21                             for piece, p_args in parent:
22                                 new_matches.extend([(piece + suffix, p_args + args) for (suffix, args) in matches])
23                             lookups.appendlist(name, (new_matches, p_pattern + pat, dict(defaults, **pattern.default_kwargs)))
24-                    for namespace, (prefix, sub_pattern) in pattern.namespace_dict.items():
25-                        namespaces[namespace] = (p_pattern + prefix, sub_pattern)
26+                    for namespace, sub_patterns in pattern.namespace_dict.items():
27+                        for prefix, sub_pattern in sub_patterns:
28+                            namespaces.setdefault(namespace, []).append((p_pattern + prefix, sub_pattern))
29                     for app_name, namespace_list in pattern.app_dict.items():
30                         apps.setdefault(app_name, []).extend(namespace_list)
31             else:
32@@ -459,9 +460,15 @@ def reverse(viewname, urlconf=None, args=None, kwargs=None, prefix=None, current
33                 pass
34 
35             try:
36-                extra, resolver = resolver.namespace_dict[ns]
37+                resolvers = resolver.namespace_dict[ns]
38+                if len(resolvers) > 1:
39+                    ns_resolvers = [RegexURLResolver(extra, ns_resolver.url_patterns)
40+                                    for extra, ns_resolver in resolvers]
41+                    resolver = RegexURLResolver('', ns_resolvers)
42+                else:
43+                    extra, resolver = resolver.namespace_dict[ns][0]
44+                    ns_pattern = ns_pattern + extra
45                 resolved_path.append(ns)
46-                ns_pattern = ns_pattern + extra
47             except KeyError, key:
48                 if resolved_path:
49                     raise NoReverseMatch(
50diff --git a/tests/regressiontests/urlpatterns_reverse/namespace_urls.py b/tests/regressiontests/urlpatterns_reverse/namespace_urls.py
51index fa892a4..2d95a8f 100644
52--- a/tests/regressiontests/urlpatterns_reverse/namespace_urls.py
53+++ b/tests/regressiontests/urlpatterns_reverse/namespace_urls.py
54@@ -6,16 +6,19 @@ from .views import view_class_instance
55 
56 
57 class URLObject(object):
58-    def __init__(self, app_name, namespace):
59+    def __init__(self, app_name, namespace, _patterns=None):
60+        if _patterns is None:
61+            _patterns = patterns('',
62+                url(r'^inner/$', 'empty_view', name='urlobject-view'),
63+                url(r'^inner/(?P<arg1>\d+)/(?P<arg2>\d+)/$', 'empty_view', name='urlobject-view'),
64+                url(r'^inner/\+\\\$\*/$', 'empty_view', name='urlobject-special-view'),
65+            )
66+        self.patterns = _patterns
67         self.app_name = app_name
68         self.namespace = namespace
69 
70     def urls(self):
71-        return patterns('',
72-            url(r'^inner/$', 'empty_view', name='urlobject-view'),
73-            url(r'^inner/(?P<arg1>\d+)/(?P<arg2>\d+)/$', 'empty_view', name='urlobject-view'),
74-            url(r'^inner/\+\\\$\*/$', 'empty_view', name='urlobject-special-view'),
75-        ), self.app_name, self.namespace
76+        return self.patterns, self.app_name, self.namespace
77     urls = property(urls)
78 
79 testobj1 = URLObject('testapp', 'test-ns1')
80@@ -25,6 +28,25 @@ default_testobj = URLObject('testapp', 'testapp')
81 otherobj1 = URLObject('nodefault', 'other-ns1')
82 otherobj2 = URLObject('nodefault', 'other-ns2')
83 
84+double_nested1 = URLObject('randomapp', 'nested',
85+    patterns('', url(r'^f1/$', 'empty_view', name='view_f1'))
86+)
87+
88+double_nested2 = URLObject('randomapp', 'nested',
89+    patterns('', url(r'^f2/$', 'empty_view', name='view_f2'))
90+)
91+
92+first_patterns = patterns('',
93+    url(r'^$', 'empty_view', name='first'),
94+    url(r'^nested1/', include(double_nested1.urls)),
95+    url(r'^nested2/', include(double_nested2.urls)),
96+)
97+first = URLObject('first', 'inc-some', first_patterns)
98+second_patterns = patterns('',
99+    url(r'^$', 'empty_view', name='second'),
100+)
101+second = URLObject('second', 'inc-some', second_patterns)
102+
103 urlpatterns = patterns('regressiontests.urlpatterns_reverse.views',
104     url(r'^normal/$', 'empty_view', name='normal-view'),
105     url(r'^normal/(?P<arg1>\d+)/(?P<arg2>\d+)/$', 'empty_view', name='normal-view'),
106@@ -55,4 +77,7 @@ urlpatterns = patterns('regressiontests.urlpatterns_reverse.views',
107     (r'^ns-outer/(?P<outer>\d+)/', include('regressiontests.urlpatterns_reverse.included_namespace_urls', namespace='inc-outer')),
108 
109     (r'^\+\\\$\*/', include('regressiontests.urlpatterns_reverse.namespace_urls', namespace='special')),
110+
111+    url(r'^first/', include(first.urls)),
112+    url(r'^second/', include(second.urls)),
113 )
114diff --git a/tests/regressiontests/urlpatterns_reverse/tests.py b/tests/regressiontests/urlpatterns_reverse/tests.py
115index a1c9244..53759cd 100644
116--- a/tests/regressiontests/urlpatterns_reverse/tests.py
117+++ b/tests/regressiontests/urlpatterns_reverse/tests.py
118@@ -392,6 +392,13 @@ class NamespaceTests(TestCase):
119         self.assertEqual('/inc70/', reverse('inc-ns5:inner-nothing', args=['70']))
120         self.assertEqual('/inc78/extra/foobar/', reverse('inc-ns5:inner-extra', args=['78','foobar']))
121 
122+    def test_namespaces_in_different_includes(self):
123+        "Namespaces declared in different places: see #17551"
124+        self.assertEqual('/first/', reverse('inc-some:first'))
125+        self.assertEqual('/second/', reverse('inc-some:second'))
126+        self.assertEqual('/first/nested1/f1/', reverse('inc-some:randomapp:view_f1'))
127+        self.assertEqual('/first/nested2/f2/', reverse('inc-some:randomapp:view_f2'))
128+
129 class RequestURLconfTests(TestCase):
130     def setUp(self):
131         self.root_urlconf = settings.ROOT_URLCONF