Ticket #13154: django-smarter-reverse.2.patch

File django-smarter-reverse.2.patch, 6.0 KB (added by Patryk Zawadzki, 13 years ago)

Updated patch containing both the change and the tests

  • tests/regressiontests/urlpatterns_reverse/views.py

     
    1313def absolute_kwargs_view(request, arg1=1, arg2=2):
    1414    return HttpResponse('')
    1515
     16def defaults_view(request, arg1, arg2):
     17    pass
     18
    1619class ViewClass(object):
    1720    def __call__(self, request, *args, **kwargs):
    1821        return HttpResponse('')
  • tests/regressiontests/urlpatterns_reverse/tests.py

     
    127127    ('kwargs_view', '/arg_view/10/', [], {'arg1':10}),
    128128    ('regressiontests.urlpatterns_reverse.views.absolute_kwargs_view', '/absolute_arg_view/', [], {}),
    129129    ('regressiontests.urlpatterns_reverse.views.absolute_kwargs_view', '/absolute_arg_view/10/', [], {'arg1':10}),
    130     ('non_path_include', '/includes/non_path_include/', [], {})
     130    ('non_path_include', '/includes/non_path_include/', [], {}),
    131131
     132    # Tests for #13154
     133    ('defaults', '/defaults_view1/3/', [], {'arg1': 3, 'arg2': 1}),
     134    ('defaults', '/defaults_view2/3/', [], {'arg1': 3, 'arg2': 2}),
     135    ('defaults', NoReverseMatch, [], {'arg1': 3, 'arg2': 3}),
     136    ('defaults', NoReverseMatch, [], {'arg2': 1}),
    132137)
    133138
    134139class NoURLPatternsTests(TestCase):
  • tests/regressiontests/urlpatterns_reverse/urls.py

     
    1919    url(r'^people/(?:name/)', empty_view, name="people2"),
    2020    url(r'^people/(?:name/(\w+)/)?', empty_view, name="people2a"),
    2121    url(r'^optional/(?P<name>.*)/(?:.+/)?', empty_view, name="optional"),
    22     url(r'^hardcoded/$', 'hardcoded/', empty_view, name="hardcoded"),
     22    url(r'^hardcoded/$', empty_view, name="hardcoded"),
    2323    url(r'^hardcoded/doc\.pdf$', empty_view, name="hardcoded2"),
    2424    url(r'^people/(?P<state>\w\w)/(?P<name>\w+)/$', empty_view, name="people3"),
    2525    url(r'^people/(?P<state>\w\w)/(?P<name>\d)/$', empty_view, name="people4"),
     
    5555    url(r'arg_view/(?P<arg1>\d+)/$', 'kwargs_view'),
    5656    url(r'absolute_arg_view/(?P<arg1>\d+)/$', absolute_kwargs_view),
    5757    url(r'absolute_arg_view/$', absolute_kwargs_view),
    58    
     58
     59    # Tests for #13154. Mixed syntax to test both ways of defining URLs.
     60    url(r'defaults_view1/(?P<arg1>\d+)/', 'defaults_view', {'arg2': 1}, name='defaults'),
     61    (r'defaults_view2/(?P<arg1>\d+)/', 'defaults_view', {'arg2': 2}, 'defaults'),
     62
    5963    url('^includes/', include(other_patterns)),
    6064
    6165)
  • django/core/urlresolvers.py

     
    206206                else:
    207207                    parent = normalize(pattern.regex.pattern)
    208208                    for name in pattern.reverse_dict:
    209                         for matches, pat in pattern.reverse_dict.getlist(name):
     209                        for matches, pat, defaults in pattern.reverse_dict.getlist(name):
    210210                            new_matches = []
    211211                            for piece, p_args in parent:
    212212                                new_matches.extend([(piece + suffix, p_args + args) for (suffix, args) in matches])
    213                             lookups.appendlist(name, (new_matches, p_pattern + pat))
     213                            lookups.appendlist(name, (new_matches, p_pattern + pat, dict(defaults, **pattern.default_kwargs)))
    214214                    for namespace, (prefix, sub_pattern) in pattern.namespace_dict.items():
    215215                        namespaces[namespace] = (p_pattern + prefix, sub_pattern)
    216216                    for app_name, namespace_list in pattern.app_dict.items():
    217217                        apps.setdefault(app_name, []).extend(namespace_list)
    218218            else:
    219219                bits = normalize(p_pattern)
    220                 lookups.appendlist(pattern.callback, (bits, p_pattern))
     220                lookups.appendlist(pattern.callback, (bits, p_pattern, pattern.default_args))
    221221                if pattern.name is not None:
    222                     lookups.appendlist(pattern.name, (bits, p_pattern))
     222                    lookups.appendlist(pattern.name, (bits, p_pattern, pattern.default_args))
    223223        self._reverse_dict = lookups
    224224        self._namespace_dict = namespaces
    225225        self._app_dict = apps
     
    310310        except (ImportError, AttributeError), e:
    311311            raise NoReverseMatch("Error importing '%s': %s." % (lookup_view, e))
    312312        possibilities = self.reverse_dict.getlist(lookup_view)
    313         for possibility, pattern in possibilities:
     313        for possibility, pattern, defaults in possibilities:
    314314            for result, params in possibility:
    315315                if args:
    316316                    if len(args) != len(params):
     
    318318                    unicode_args = [force_unicode(val) for val in args]
    319319                    candidate =  result % dict(zip(params, unicode_args))
    320320                else:
    321                     if set(kwargs.keys()) != set(params):
     321                    if set(kwargs.keys() + defaults.keys()) != set(params + defaults.keys()):
    322322                        continue
     323                    matches = True
     324                    for k, v in defaults.items():
     325                        if kwargs.get(k, v) != v:
     326                            matches = False
     327                            break
     328                    if not matches:
     329                        continue
    323330                    unicode_kwargs = dict([(k, force_unicode(v)) for (k, v) in kwargs.items()])
    324331                    candidate = result % unicode_kwargs
    325332                if re.search(u'^%s' % pattern, candidate, re.UNICODE):
Back to Top