#17914: reverse() does not support namespaced view references
-------------------------------------------------+--------------------
     Reporter:  Bradley Ayers <bradley.ayers@…>  |      Owner:  nobody
         Type:  Bug                              |     Status:  new
    Component:  Core (URLs)                      |    Version:  1.3
     Severity:  Normal                           |   Keywords:
 Triage Stage:  Unreviewed                       |  Has patch:  0
Easy pickings:  0                                |      UI/UX:  0
-------------------------------------------------+--------------------
 It's not possible to reverse a URL by passing a function reference to
 reverse()
 that's hooked into the URLconf under a namespace.

 Consider the trivial Django project (that doesn't work):

 {{{
 # urls.py
 from django.conf.urls.defaults import patterns, include
 from django.core.urlresolvers import reverse
 from django.http import HttpResponse

 def view(request):
     # Return the URL to this view
     return HttpResponse(reverse(view))

 level2 = patterns('',
     (r'^2/', view)
 )

 urlpatterns = patterns('',
     (r'^1/', include(level2, namespace="foo"))
 )
 }}}

 Removing ``, namespace="foo"`` will make it work.

 My understanding of why this happens, is that `reverse()` traverses
 `RegexURLResolver`s
 *only* for strings. Function references are passed directly to the root
 `RegexURLResolver.reverse`
 method.:

 {{{
 # from django/core/urlresolvers.py ~ line 432

 if not isinstance(viewname, basestring):
     view = viewname
 else:
     # <snip> -- resolver traversal happens here to honor namespaces
     # `resolver` is reassigned to last RegexURLResolver in namespace chain

 return iri_to_uri(resolver._reverse_with_prefix(view, prefix, *args,
 **kwargs))
 }}}

 Obviously traversing namespaces isn't possible for a function reference,
 so what's needed is to add *all* descendent view references into each
 `RegexURLResolver`'s
 `reverse_dict` dictionary.

 Populating `reverse_dict` is lazy and happens on first access, the work is
 performed in `RegexURLResolver._populate`:

 {{{
 # django/core/urlresolvers.py ~ line 237
 def _populate(self):
     # <snip>
     for pattern in reversed(self.url_patterns):
         # <snip>
         if isinstance(pattern, RegexURLResolver):
             if pattern.namespace:
                 # <snip> -- tldr `self.reverse_dict` isn't populated,
 `pattern` (the
                 #           RegexURLResolver) is instead stored in
 `self.namespace_dict`
             else:
                 # <snip> -- tldr `self.reverse_dict` *is* populated with
 the keys
                 #           being the name of each URL (or the function
 reference)
                 #           defined in this level. (i.e. only children,
 not all descendants)
         else:
             # <snip> -- tldr `self.reverse_dict` is again populated
 }}}

 This combination of behaviour by `RegexURLResolver._populate` and
 `reverse()`
 leads to the problem.

-- 
Ticket URL: <https://code.djangoproject.com/ticket/17914>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.

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

Reply via email to