Ticket #9038: 9038-r9084.diff
File 9038-r9084.diff, 6.0 KB (added by , 16 years ago) |
---|
-
django/core/urlresolvers.py
11 11 12 12 from django.http import Http404 13 13 from django.core.exceptions import ImproperlyConfigured, ViewDoesNotExist 14 from django.utils.datastructures import MultiValueDict 14 15 from django.utils.encoding import iri_to_uri, force_unicode, smart_str 15 16 from django.utils.functional import memoize 16 17 from django.utils.regex_helper import normalize … … 144 145 self.urlconf_name = urlconf_name 145 146 self.callback = None 146 147 self.default_kwargs = default_kwargs or {} 147 self._reverse_dict = {}148 self._reverse_dict = MultiValueDict() 148 149 149 150 def __repr__(self): 150 151 return '<%s %s %s>' % (self.__class__.__name__, self.urlconf_name, self.regex.pattern) … … 162 163 for piece, p_args in parent: 163 164 new_matches.extend([(piece + suffix, p_args + args) 164 165 for (suffix, args) in matches]) 165 self._reverse_dict [name] = new_matches, p_pattern + pat166 self._reverse_dict.appendlist(name, (new_matches, p_pattern + pat)) 166 167 else: 167 168 bits = normalize(p_pattern) 168 self._reverse_dict [pattern.callback] = bits, p_pattern169 self._reverse_dict [pattern.name] = bits, p_pattern169 self._reverse_dict.appendlist(pattern.callback, (bits, p_pattern)) 170 self._reverse_dict.appendlist(pattern.name, (bits, p_pattern)) 170 171 return self._reverse_dict 171 172 reverse_dict = property(_get_reverse_dict) 172 173 … … 223 224 lookup_view = get_callable(lookup_view, True) 224 225 except (ImportError, AttributeError), e: 225 226 raise NoReverseMatch("Error importing '%s': %s." % (lookup_view, e)) 226 possibilities, pattern = self.reverse_dict.get(lookup_view, [(), ()]) 227 for result, params in possibilities: 228 if args: 229 if len(args) != len(params): 230 continue 231 unicode_args = [force_unicode(val) for val in args] 232 candidate = result % dict(zip(params, unicode_args)) 233 else: 234 if set(kwargs.keys()) != set(params): 235 continue 236 unicode_kwargs = dict([(k, force_unicode(v)) for (k, v) in kwargs.items()]) 237 candidate = result % unicode_kwargs 238 if re.search(u'^%s' % pattern, candidate, re.UNICODE): 239 return candidate 227 possibilities = self.reverse_dict.getlist(lookup_view) 228 for possibility, pattern in possibilities: 229 for result, params in possibility: 230 if args: 231 if len(args) != len(params): 232 continue 233 unicode_args = [force_unicode(val) for val in args] 234 candidate = result % dict(zip(params, unicode_args)) 235 else: 236 if set(kwargs.keys()) != set(params): 237 continue 238 unicode_kwargs = dict([(k, force_unicode(v)) for (k, v) in kwargs.items()]) 239 candidate = result % unicode_kwargs 240 if re.search(u'^%s' % pattern, candidate, re.UNICODE): 241 return candidate 240 242 raise NoReverseMatch("Reverse for '%s' with arguments '%s' and keyword " 241 243 "arguments '%s' not found." % (lookup_view, args, kwargs)) 242 244 -
tests/regressiontests/urlpatterns_reverse/views.py
1 1 def empty_view(request, *args, **kwargs): 2 2 pass 3 4 def kwargs_view(request, arg1=1, arg2=2): 5 pass 6 7 def absolute_kwargs_view(request, arg1=1, arg2=2): 8 pass -
tests/regressiontests/urlpatterns_reverse/tests.py
65 65 ('extra-places', '/e-places/10/', ['10'], {}), 66 66 ('extra-people', '/e-people/fred/', ['fred'], {}), 67 67 ('extra-people', '/e-people/fred/', [], {'name': 'fred'}), 68 69 # Regression for #9038 70 # These views are resolved by method name. Each method is deployed twice - 71 # once with an explicit argument, and once using the default value on 72 # the method. This is potentially ambiguous, as you have to pick the 73 # correct view for the arguments provided. 74 ('kwargs_view', '/arg_view/', [], {}), 75 ('kwargs_view', '/arg_view/10/', [], {'arg1':10}), 76 ('regressiontests.urlpatterns_reverse.views.absolute_kwargs_view', '/absolute_arg_view/', [], {}), 77 ('regressiontests.urlpatterns_reverse.views.absolute_kwargs_view', '/absolute_arg_view/10/', [], {'arg1':10}), 78 68 79 ) 69 80 70 81 class URLPatternReverse(TestCase): -
tests/regressiontests/urlpatterns_reverse/urls.py
1 1 from django.conf.urls.defaults import * 2 from views import empty_view 2 from views import empty_view, absolute_kwargs_view 3 3 4 4 urlpatterns = patterns('', 5 5 url(r'^places/(\d+)/$', empty_view, name='places'), … … 45 45 46 46 # This is non-reversible, but we shouldn't blow up when parsing it. 47 47 url(r'^(?:foo|bar)(\w+)/$', empty_view, name="disjunction"), 48 49 # Regression views for #9038. See tests for more details 50 url(r'arg_view/$', 'kwargs_view'), 51 url(r'arg_view/(?P<arg1>\d+)/$', 'kwargs_view'), 52 url(r'absolute_arg_view/(?P<arg1>\d+)/$', absolute_kwargs_view), 53 url(r'absolute_arg_view/$', absolute_kwargs_view), 54 48 55 )