Author: mtredinnick
Date: 2008-09-27 01:14:11 -0500 (Sat, 27 Sep 2008)
New Revision: 9087

Modified:
   django/trunk/django/core/urlresolvers.py
   django/trunk/tests/regressiontests/urlpatterns_reverse/tests.py
   django/trunk/tests/regressiontests/urlpatterns_reverse/urls.py
   django/trunk/tests/regressiontests/urlpatterns_reverse/views.py
Log:
Fixed #9038 -- Correctly handle URL patterns with the same name (or view name),
declared independently and that differ only by argument signatures.

Patch from Russell Keith-Magee.


Modified: django/trunk/django/core/urlresolvers.py
===================================================================
--- django/trunk/django/core/urlresolvers.py    2008-09-27 05:57:10 UTC (rev 
9086)
+++ django/trunk/django/core/urlresolvers.py    2008-09-27 06:14:11 UTC (rev 
9087)
@@ -11,6 +11,7 @@
 
 from django.http import Http404
 from django.core.exceptions import ImproperlyConfigured, ViewDoesNotExist
+from django.utils.datastructures import MultiValueDict
 from django.utils.encoding import iri_to_uri, force_unicode, smart_str
 from django.utils.functional import memoize
 from django.utils.regex_helper import normalize
@@ -144,7 +145,7 @@
         self.urlconf_name = urlconf_name
         self.callback = None
         self.default_kwargs = default_kwargs or {}
-        self._reverse_dict = {}
+        self._reverse_dict = MultiValueDict()
 
     def __repr__(self):
         return '<%s %s %s>' % (self.__class__.__name__, self.urlconf_name, 
self.regex.pattern)
@@ -162,11 +163,11 @@
                         for piece, p_args in parent:
                             new_matches.extend([(piece + suffix, p_args + args)
                                     for (suffix, args) in matches])
-                        self._reverse_dict[name] = new_matches, p_pattern + pat
+                        self._reverse_dict.appendlist(name, (new_matches, 
p_pattern + pat))
                 else:
                     bits = normalize(p_pattern)
-                    self._reverse_dict[pattern.callback] = bits, p_pattern
-                    self._reverse_dict[pattern.name] = bits, p_pattern
+                    self._reverse_dict.appendlist(pattern.callback, (bits, 
p_pattern))
+                    self._reverse_dict.appendlist(pattern.name, (bits, 
p_pattern))
         return self._reverse_dict
     reverse_dict = property(_get_reverse_dict)
 
@@ -223,20 +224,21 @@
             lookup_view = get_callable(lookup_view, True)
         except (ImportError, AttributeError), e:
             raise NoReverseMatch("Error importing '%s': %s." % (lookup_view, 
e))
-        possibilities, pattern = self.reverse_dict.get(lookup_view, [(), ()])
-        for result, params in possibilities:
-            if args:
-                if len(args) != len(params):
-                    continue
-                unicode_args = [force_unicode(val) for val in args]
-                candidate =  result % dict(zip(params, unicode_args))
-            else:
-                if set(kwargs.keys()) != set(params):
-                    continue
-                unicode_kwargs = dict([(k, force_unicode(v)) for (k, v) in 
kwargs.items()])
-                candidate = result % unicode_kwargs
-            if re.search(u'^%s' % pattern, candidate, re.UNICODE):
-                return candidate
+        possibilities = self.reverse_dict.getlist(lookup_view)
+        for possibility, pattern in possibilities:
+            for result, params in possibility:
+                if args:
+                    if len(args) != len(params):
+                        continue
+                    unicode_args = [force_unicode(val) for val in args]
+                    candidate =  result % dict(zip(params, unicode_args))
+                else:
+                    if set(kwargs.keys()) != set(params):
+                        continue
+                    unicode_kwargs = dict([(k, force_unicode(v)) for (k, v) in 
kwargs.items()])
+                    candidate = result % unicode_kwargs
+                if re.search(u'^%s' % pattern, candidate, re.UNICODE):
+                    return candidate
         raise NoReverseMatch("Reverse for '%s' with arguments '%s' and keyword 
"
                 "arguments '%s' not found." % (lookup_view, args, kwargs))
 

Modified: django/trunk/tests/regressiontests/urlpatterns_reverse/tests.py
===================================================================
--- django/trunk/tests/regressiontests/urlpatterns_reverse/tests.py     
2008-09-27 05:57:10 UTC (rev 9086)
+++ django/trunk/tests/regressiontests/urlpatterns_reverse/tests.py     
2008-09-27 06:14:11 UTC (rev 9087)
@@ -65,6 +65,17 @@
     ('extra-places', '/e-places/10/', ['10'], {}),
     ('extra-people', '/e-people/fred/', ['fred'], {}),
     ('extra-people', '/e-people/fred/', [], {'name': 'fred'}),
+
+    # Regression for #9038
+    # These views are resolved by method name. Each method is deployed twice -
+    # once with an explicit argument, and once using the default value on
+    # the method. This is potentially ambiguous, as you have to pick the
+    # correct view for the arguments provided.
+    ('kwargs_view', '/arg_view/', [], {}),
+    ('kwargs_view', '/arg_view/10/', [], {'arg1':10}),
+    ('regressiontests.urlpatterns_reverse.views.absolute_kwargs_view', 
'/absolute_arg_view/', [], {}),
+    ('regressiontests.urlpatterns_reverse.views.absolute_kwargs_view', 
'/absolute_arg_view/10/', [], {'arg1':10}),
+
 )
 
 class URLPatternReverse(TestCase):

Modified: django/trunk/tests/regressiontests/urlpatterns_reverse/urls.py
===================================================================
--- django/trunk/tests/regressiontests/urlpatterns_reverse/urls.py      
2008-09-27 05:57:10 UTC (rev 9086)
+++ django/trunk/tests/regressiontests/urlpatterns_reverse/urls.py      
2008-09-27 06:14:11 UTC (rev 9087)
@@ -1,5 +1,5 @@
 from django.conf.urls.defaults import *
-from views import empty_view
+from views import empty_view, absolute_kwargs_view
 
 urlpatterns = patterns('',
     url(r'^places/(\d+)/$', empty_view, name='places'),
@@ -45,4 +45,11 @@
 
     # This is non-reversible, but we shouldn't blow up when parsing it.
     url(r'^(?:foo|bar)(\w+)/$', empty_view, name="disjunction"),
+
+    # Regression views for #9038. See tests for more details
+    url(r'arg_view/$', 'kwargs_view'),
+    url(r'arg_view/(?P<arg1>\d+)/$', 'kwargs_view'),
+    url(r'absolute_arg_view/(?P<arg1>\d+)/$', absolute_kwargs_view),
+    url(r'absolute_arg_view/$', absolute_kwargs_view),
+
 )

Modified: django/trunk/tests/regressiontests/urlpatterns_reverse/views.py
===================================================================
--- django/trunk/tests/regressiontests/urlpatterns_reverse/views.py     
2008-09-27 05:57:10 UTC (rev 9086)
+++ django/trunk/tests/regressiontests/urlpatterns_reverse/views.py     
2008-09-27 06:14:11 UTC (rev 9087)
@@ -1,2 +1,8 @@
 def empty_view(request, *args, **kwargs):
     pass
+
+def kwargs_view(request, arg1=1, arg2=2):
+    pass
+
+def absolute_kwargs_view(request, arg1=1, arg2=2):
+    pass


--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"Django updates" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/django-updates?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to