Ticket #17914: 17914.patch

File 17914.patch, 8.0 KB (added by Bradley Ayers <bradley.ayers@…>, 3 years ago)

fix + tests

  • tests/regressiontests/urlpatterns_reverse/views.py

     
    2626        return HttpResponse('')
    2727
    2828view_class_instance = ViewClass()
     29view_class_instance2 = ViewClass()
    2930
    3031class LazyRedirectView(RedirectView):
    3132    url = reverse_lazy('named-lazy-url-redirected-to')
  • tests/regressiontests/urlpatterns_reverse/namespace_urls.py

     
    5454
    5555    (r'^ns-outer/(?P<outer>\d+)/', include('regressiontests.urlpatterns_reverse.included_namespace_urls', namespace='inc-outer')),
    5656
    57     (r'^\+\\\$\*/', include('regressiontests.urlpatterns_reverse.namespace_urls', namespace='special')),
     57    (r'^\+\\\$\*/included/', include('regressiontests.urlpatterns_reverse.included_namespace_urls', namespace='special')),
    5858)
  • tests/regressiontests/urlpatterns_reverse/tests.py

     
    4747
    4848    # Nested namespaces
    4949    ('/ns-included1/test3/inner/42/37/', 'urlobject-view', 'testapp', 'inc-ns1:test-ns3', 'empty_view', tuple(), {'arg1': '42', 'arg2': '37'}),
    50     ('/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'}),
    5150
    5251    # Namespaces capturing variables
    5352    ('/inc70/', 'inner-nothing', None, 'inc-ns5', views.empty_view, tuple(), {'outer': '70'}),
     
    278277class NamespaceTests(TestCase):
    279278    urls = 'regressiontests.urlpatterns_reverse.namespace_urls'
    280279
     280    def test_function_reference(self):
     281        self.assertEqual(reverse(views.view_class_instance2), '/+%5C$*/included/view_class/level2/')
     282
    281283    def test_ambiguous_object(self):
    282284        "Names deployed via dynamic URL objects that require namespaces can't be resolved"
    283285        self.assertRaises(NoReverseMatch, reverse, 'urlobject-view')
     
    346348        self.assertEqual('/ns-included1/test3/inner/42/37/', reverse('inc-ns1:test-ns3:urlobject-view', kwargs={'arg1':42, 'arg2':37}))
    347349        self.assertEqual('/ns-included1/test3/inner/+%5C$*/', reverse('inc-ns1:test-ns3:urlobject-special-view'))
    348350
    349     def test_nested_namespace_pattern(self):
    350         "Namespaces can be nested"
    351         self.assertEqual('/ns-included1/ns-included4/ns-included1/test3/inner/', reverse('inc-ns1:inc-ns4:inc-ns1:test-ns3:urlobject-view'))
    352         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]))
    353         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}))
    354         self.assertEqual('/ns-included1/ns-included4/ns-included1/test3/inner/+%5C$*/', reverse('inc-ns1:inc-ns4:inc-ns1:test-ns3:urlobject-special-view'))
    355 
    356351    def test_app_lookup_object(self):
    357352        "A default application namespace can be used for lookup"
    358353        self.assertEqual('/default/inner/', reverse('testapp:urlobject-view'))
  • tests/regressiontests/urlpatterns_reverse/included_namespace_urls.py

     
    33from django.conf.urls import patterns, url, include
    44
    55from .namespace_urls import URLObject
    6 from .views import view_class_instance
     6from .views import view_class_instance, view_class_instance2
    77
    88
    99testobj3 = URLObject('testapp', 'test-ns3')
    1010
     11level2_patterns = patterns("",
     12    (r'^level2/$', view_class_instance2)
     13)
     14
    1115urlpatterns = patterns('regressiontests.urlpatterns_reverse.views',
    1216    url(r'^normal/$', 'empty_view', name='inc-normal-view'),
    1317    url(r'^normal/(?P<arg1>\d+)/(?P<arg2>\d+)/$', 'empty_view', name='inc-normal-view'),
     
    1822    url(r'^no_kwargs/(\d+)/(\d+)/$', 'empty_view', name='inc-no-kwargs'),
    1923
    2024    url(r'^view_class/(?P<arg1>\d+)/(?P<arg2>\d+)/$', view_class_instance, name='inc-view-class'),
     25    url(r'^view_class/', include(level2_patterns)),
    2126
    2227    (r'^test3/', include(testobj3.urls)),
    2328    (r'^ns-included3/', include('regressiontests.urlpatterns_reverse.included_urls', namespace='inc-ns3')),
    24     (r'^ns-included4/', include('regressiontests.urlpatterns_reverse.namespace_urls', namespace='inc-ns4')),
    2529)
    2630
  • django/core/urlresolvers.py

     
    77    (view_function, function_args, function_kwargs)
    88"""
    99
     10from itertools import ifilter
    1011import re
    1112from threading import local
    1213
     
    248249                    namespaces[pattern.namespace] = (p_pattern, pattern)
    249250                    if pattern.app_name:
    250251                        apps.setdefault(pattern.app_name, []).append(pattern.namespace)
     252                    # Since a namespace has been provided for the included resolver,
     253                    # we can rely on urlresolvers.reverse() to traverse the tree
     254                    # to honor and find the correct resolver to finally be able to
     255                    # call resolver.reverse(name).
     256                    # However when reversing a callable, no namespace information
     257                    # is attached to the callable so all lookups for all descendant
     258                    # views functions *must* be included in each resolver.
     259                    include_lookups = ifilter(callable, pattern.reverse_dict)
    251260                else:
    252                     parent = normalize(pattern.regex.pattern)
    253                     for name in pattern.reverse_dict:
    254                         for matches, pat, defaults in pattern.reverse_dict.getlist(name):
    255                             new_matches = []
    256                             for piece, p_args in parent:
    257                                 new_matches.extend([(piece + suffix, p_args + args) for (suffix, args) in matches])
    258                             lookups.appendlist(name, (new_matches, p_pattern + pat, dict(defaults, **pattern.default_kwargs)))
    259261                    for namespace, (prefix, sub_pattern) in pattern.namespace_dict.items():
    260262                        namespaces[namespace] = (p_pattern + prefix, sub_pattern)
    261263                    for app_name, namespace_list in pattern.app_dict.items():
    262264                        apps.setdefault(app_name, []).extend(namespace_list)
     265                    # When no namespace is provided, *all* the patterns in the
     266                    # included resolver should be available in this resolver.
     267                    include_lookups = iter(pattern.reverse_dict)
     268                # Add each of the child lookups to this resolver, being careful
     269                # to add appropriate URL and regex prefixes so reversing results
     270                # are correct.
     271                parent = normalize(pattern.regex.pattern)
     272                for name in include_lookups:
     273                    for matches, pat, defaults in pattern.reverse_dict.getlist(name):
     274                        new_matches = []
     275                        for piece, p_args in parent:
     276                            new_matches.extend([(piece + suffix, p_args + args) for (suffix, args) in matches])
     277                        lookups.appendlist(name, (new_matches, p_pattern + pat, dict(defaults, **pattern.default_kwargs)))
    263278            else:
    264279                bits = normalize(p_pattern)
    265280                lookups.appendlist(pattern.callback, (bits, p_pattern, pattern.default_args))
Back to Top